题目大意:每一个01串中最多含有一个‘*’,‘*’既可表示0也可表示1,给出一些等长的这样的01串,问最少能用多少个这样的串表示出这些串。如:000、010、0*1表示000、010、001、011,最少只需用00*、01*这两个即可表示出来。
题目分析:如果有两个串只有一个位置上的数字不同,就可以用*代替这个位置上的数,这样就能把两个串用一个串表示出来。因为要找最少的数目,当然‘*’用的越多越好,也就是说只需找出最多的对数,然后再加上不用‘*’表示的串的数目便是最小值。
代码如下:
# include<iostream> # include<cstdio> # include<vector> # include<cstring> # include<algorithm> using namespace std; vector<int>b; int vis[1005]; int n,m,a[1500][1500],s[1500],t[1005]; int A[11]={1,2,4,8,16,32,64,128,256,512,1024}; void f(string p) { int r=0; for(int i=0;i<m;++i) r=r*2+p[i]-'0'; b.push_back(r); } bool ok(int x,int y) { int z=x^y; for(int i=0;i<11;++i) if(z==A[i]) return true; return false; } void setG() { memset(a,0,sizeof(a)); for(int i=0;i<n;++i) for(int j=i+1;j<n;++j) if(ok(b[i],b[j])) a[i][j]=a[j][i]=1; } bool match(int u) { for(int v=0;v<n;++v){ if(!a[u][v]) continue; if(vis[v]) continue; vis[v]=1; if(t[v]==-1||match(t[v])){ t[v]=u; s[u]=v; return true; } } return false; } void solve() { memset(s,-1,sizeof(s)); memset(t,-1,sizeof(t)); int ans=0; for(int i=0;i<n;++i) if(s[i]==-1){ memset(vis,0,sizeof(vis)); if(match(i)) ++ans; } ans/=2; for(int i=0;i<n;++i) if(t[i]==-1) ++ans; printf("%d ",ans); } int main() { string p; while(scanf("%d%d",&m,&n)&&(n+m)) { b.clear(); for(int i=0;i<n;++i){ cin>>p; int j; for(j=0;j<m;++j) if(p[j]=='*') break; if(j==m) f(p); else{ p[j]='0'; f(p); p[j]='1'; f(p); } } sort(b.begin(),b.end()); n=unique(b.begin(),b.end())-b.begin(); setG(); solve(); } return 0; }