题意:给定m个长度为n的串,串只包含0,1,*,三个字符。其中,*号位置代表0或1。如果两个串只有一位不同,则可以“消去”,合并成一个带*号的。求最少几次可以合并所有的串
思路:http://blog.csdn.net/wcr1996/article/details/48091795
这种题目没想到还能这么构图,位运算真是让人眼前一亮。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 2100;
int map[maxn][maxn],match[maxn],vis[maxn];
int set[maxn];
char s[20];
int n,m;
bool dfs(int u)
{
for(int i=0;i<maxn;i++)
{
if(map[u][i]&&!vis[i])
{
vis[i]=1;
if(match[i]==-1||dfs(match[i]))
{
match[i]=u;
return true;
}
}
}
return false;
}
int Hungarian()
{
int ans=0;
memset(match,-1,sizeof(match));
for(int i=0;i<maxn;i++)//从所有点?
{
memset(vis,0,sizeof(vis));
if(dfs(i))ans++;
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)&&(n+m))//m个长度为n
{
memset(set,0,sizeof(set));
memset(map,0,sizeof(map));
for(int i=0;i<m;i++)
{
scanf("%s",s);
int temp=0,pos=-1;
for(int j=0;j<n;j++)
if(s[j]=='1')temp |= (1<<j);
else if(s[j]=='*')pos=j;
set[temp]=1;
if(pos!=-1)
{
temp|=1<<pos;
set[temp]=1;
}
}
m=0;
for(int i=0;i<maxn;i++)
{
if(set[i])
{
m++;
int temp;
for(int j=0;j<n;j++)
{
temp=i^(1<<j);
if(set[temp])map[i][temp]=1;
}
}
}
int ans = Hungarian();
printf("%d\n",m-ans/2);
}
}