题意:迈克有一台可以净化奶酪的机器,用二进制表示净化的奶酪的编号。但是,在某些二进制串中可能包含有‘*'。例如01*100,'*'其实就代表可以取0,1两种情况--> 010100 和011100。现在由于迈克不小心,他以同样的方式弄脏了某些奶酪,问你最少用多少次操作就可以把弄脏的奶酪全净化好。(没有被弄脏过的奶酪不能净化。弄脏过的奶酪可以多次净化。)
题解:净化的时候,净化的时候每次尽量用包含*的二进制串(因为它可以净化两块奶酪)。
操作数 = 总污染数 - 2 * 最大匹配 + 最大匹配。 (代码中求出的最大匹配数是实际值的2倍)。判断二进制是否之差一位C=A^B ; C&&((C&(C-1))==0)
#include <algorithm>
#include <iostream>
using namespace std;
#define N 2050
bool vis[N];
int num[N], match[N], link[N][N];
int m, n, cnt;
bool find_path ( int u )
{
for ( int i = 1; i <= link[u][0]; i++ )
{
int v = link[u][i];
if ( ! vis[v] )
{
vis[v] = true;
if ( !match[v] || find_path(match[v]) )
{
match[v] = u;
return true;
}
}
}
return false;
}
int Hungary ()
{
int ans = 0;
memset(match,0,sizeof(match));
for ( int i = 1; i <= cnt; i++ )
{
memset(vis,0,sizeof(vis));
if ( find_path ( i ) ) ans++;
}
return ans;
}
int main()
{
char oper[12];
int i, j, k;
while ( scanf("%d %d",&n, &m) && (m+n) )
{
cnt = 0;
memset(link,0,sizeof(link));
memset(num,0,sizeof(num));
for ( i = 1; i <= m; i++ )
{
scanf("%s",oper);
cnt++; k = -1;
for ( j = 0; j < n; j++ )
{
if ( oper[j] == '*' ) k = j;
else num[cnt] |= ((oper[j]-'0')<<j);
}
if ( k != -1 )
{
cnt++;
num[cnt] = (num[cnt-1] | (1<<k));
}
}
sort(num+1,num+1+cnt);
num[0] = -1;
for ( j = 0, i = 1; i <= cnt; i++ )
{
if ( num[j] != num[i] )
num[++j] = num[i];
}
cnt = j;
for ( i = 1; i <= cnt; i++ )
{
for ( j = 1; j <= cnt; j++ )
{
int t = num[i] ^ num[j];
if ( t && ((t&(t-1)) == 0) )
{
link[i][0]++;
link[i][link[i][0]] = j;
}
}
}
printf("%d\n",cnt-Hungary()/2);
}
return 0;
}