题目类型:二分图-最大边匹配的变形
解题思路:
(1)numcount(坏的cheese数)- maxmatch(此处是指被匹配的所有顶点)+maxmatch/2;其中numcount-maxmatch是没有匹配的顶点,即必须采取的操作
而maxmatch/2则是可以通过'*'来实现的操作。
(2)建边:当两个整数只有一位不相同时连接一条边
(3)重边的判断:借助数组refinal实现
建边的时候有一个小优化,就是求A,B的2进制表示是否只差1位
C=A^B;
C&&((C&(C-1))==0)的结果就表示他们是否只差1位
下面稍微证明一下
1.如果C=0,那么很明显A,B的2进制表示不可能只差1位
可是0&(-1)=0...
2.对于(1<<K)来说,在满足1的条件下(K>=0)必然有(1<<K)&((1<<K)-1)=0
100000
&011111
=------
000000
3.至于为什么要xor,看看下面的例子就明白了~
10010
^10011
------
00001
10000
^11000
-------
01000
#include <iostream>
#include <string.h>
//#include <conio.h>
using namespace std;
#define marray 1025 //最多有十个开关,所以是2^10,不要设成M的两倍,否则会超时
int map[marray][marray];
bool final[marray];
int match[marray];
int num[marray];
bool refinal[marray]; //加入此数组主要用于重边的判断
int n,m;
int numcount = 0; //记录顶点的个数,即被感染的cheese的总数
char str[15];
bool isConnect(int c) //判断两个整数是否只有一位不同 (位运算实现)
{
return (c&&((c&(c-1))==0));
}
int strtoint(char * s) //将位串转换为相应的整数
{
int L=strlen(s),i=0,j=0; //使用strlen,不要使用sizeof实现
int sum=0;
for(i=L-1;i>=0;i--,j++) //string类型的最高位为位串的最低位
{
if(s[i]=='1') sum+=(1<<j); //<<是左移位操作符,右操作数j指明要移动的位数,左移相当于乘2,右移相当于除2
}
return sum;
}
bool DFS(int p)
{
int i,j;
int t,k;
for(i=1;i<=numcount;++i)
{
if(map[p][i]&& !final[i])
{
final[i]=true;
t = match[i];
match[i] = p;
if(t==0 || DFS(t)) return true;
match[i] = t; //注意二分匹配时不必在此处回溯时改变final的值,如果从一个点A出发,没有找到增广路径,那么无论再从别的点出发找到多少增广路径来改变现在的匹配,从A出发都永远找不到增广路径。
}
}
return false;
}
int mat()
{
int maxmatch = 0;
int i,j;
for(i=1;i<=numcount;++i)
{
memset(final,0,sizeof(final));
if(DFS(i)) maxmatch++;
}
return maxmatch;
}
int main()
{
//freopen("1.txt","r",stdin);
int i,j,k;
bool flag;
int v;
int strsize;
while(scanf("%d%d",&n,&m)!=-1)
{
if(n==0 && m==0)
break;
numcount = 0;
memset(map,0,sizeof(map));
memset(match,0,sizeof(match));
memset(refinal,0,sizeof(refinal));
for(i=1;i<=m;++i)
{
flag = false;
scanf("%s",str);
strsize = strlen(str); //使用strlen,此处不要使用sizeof
for(j=0;j<strsize;++j)
{
if(str[j]=='*')
{
flag = true;
v = j;
break;
}
}
if(flag)
{
str[v]='0';
refinal[strtoint(str)] = true;
str[v]='1';
refinal[strtoint(str)] = true;
}
else
{
refinal[strtoint(str)] = true;
}
}
for(i=0;i<=marray;++i)
{
if(refinal[i])
{
numcount++;
num[numcount] = i;
}
}
for(i=1;i<=numcount;++i)
{
for(j=1;j<=numcount;++j)
{
if(isConnect(num[i]^num[j]))
map[i][j]=1;
}
}
cout<<(numcount-mat()/2)<<endl;
}
//getch();
return 0;
}