题意:
会给出M个串,我们要做的就是将这M个串给清除了。对于任意两个串,若二进制形式只有一位不一样,那么这两个串可以在一次操作消除,否则每个操作只能消除一个串。
3 3
*01
100
011
可以代表的串是
001
101
100
011
那么我们可以先用 10*把 101 和 100 消除了,再用 0*1把001 和 011 消除了。故操作次数为 2。
解题思路:
我们可以将所有的串先化为整数,并去重。然后对二进制形式只有一位不一样的两个数,我们由含有偶数个1的数向含有奇数个1的数连边,这样就确保了一定是二分图,因为不存在同含奇数个1或同含偶数个1 的数只相差一位。最后进行求最大匹配,既是我们可以省去的操作数。所以我们求得最大独立集才是最终答案。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define Maxn 1200
using namespace std;
int graphic[Maxn][Maxn],vi[Maxn],match[Maxn],n,m,ans[Maxn],e;
int dfs(int u)//匈牙利算法
{
int i;
for(i=;i<=e;i++)
{
if(!vi[i]&&graphic[u][i])
{
vi[i]=;
if(match[i]==-||dfs(match[i]))
{
match[i]=u;
return ;
}
}
}
return ;
}
int main()
{
int i,j,k,Case=,a,b,num1,num2,Exp[];
char str[];
Exp[]=;
for(i=;i<=;i++)
Exp[i]=Exp[i-]*;
while(scanf("%d%d",&n,&m),n||m)
{
memset(match,-,sizeof(match));
memset(graphic,,sizeof(graphic));
memset(ans,,sizeof(ans));
e=;
for(i=;i<=m;i++)
{
scanf("%s",&str);
num1=;num2=-;
for(j=n-;j>=;j--)
{
if(str[j]!='*')
num1+=Exp[n-j-]*(str[j]-'');
else
num2=Exp[n-j-];
}
ans[++e]=num1;
if(num2!=-)
ans[++e]=num1+num2;
}
int num=;
sort(ans+,ans+e+);//排完序后进行去重
for(i=;i<=e;i++)
if(ans[i]!=ans[num])
ans[++num]=ans[i];
e=num;
for(i=;i<=e;i++)
{
for(j=i+;j<=e;j++)
{
int temp=(ans[i]^ans[j]);//找出不同位
if((temp&(temp-))==)//若不同位只有一位,则为0
{
temp=ans[i];
num=;
while(temp)//求出二进制数1的个数
{
num++;
temp=temp&(temp-);
}
if(num%==)//判断1的个数是奇数还是偶数
graphic[i][j]=;
else
graphic[j][i]=;
}
}
}
num=;
for(i=;i<=e;i++)
{
memset(vi,,sizeof(vi));
if(dfs(i))
num++;
}
printf("%d\n",e-num);
}
return ;
}