题意:m个长度为n的2进制数,可能某一位是*代替(代表*=1和*=0都被包含了)。要求用最少的另外一些二进制数(也可以某一位被*代替)将原来的那些覆盖(且只能覆盖一次),且要求不能覆盖原本不存在的二进制数。

题解:由于*可以覆盖两个二进制数,所以*用的最大的时候就是题目要求的解。如果两个二进制数只相差一位,那么这两个二进制数就可以用一个带*的二进制数就可以覆盖了,由于要求不能覆盖两次,实际上就成了求二分图最大匹配。最后匹配可以覆盖掉ret*2个,剩下的就只能用单一不含*的去覆盖了。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=2002;
 6 bool chk[N],g[N][N];
 7 int link[N],n;
 8 bool findpath(int x)
 9 {
10     for(int y=0; y<n; y++)
11     {
12         if(g[x][y]&&!chk[y])
13         {
14             chk[y]=true;
15             if(link[y]==-1||findpath(link[y]))
16             {
17                 link[y]=x;
18                 return true;
19             }
20         }
21     }
22     return false;
23 }
24 int maxmatch()
25 {
26     memset(link,-1,sizeof(link));
27     int ret=0;
28     for(int x=0; x<n; x++)
29     {
30         memset(chk,false,sizeof(chk));
31         if(findpath(x))
32             ret++;
33     }
34     return ret;
35 }
36 struct data
37 {
38     char s[N];
39     bool operator<(const data &ne)const
40     {
41         return strcmp(s,ne.s)<=0;
42     }
43 }po[N];
44 bool check(char s1[],char s2[])
45 {
46     int ret=0;
47     for(int i=0; s1[i]!='\0'; i++)
48         if(s1[i]!=s2[i])
49             ret++;
50     return ret==1;
51 }
52 int main()
53 {
54     int nn,mm;
55     while(scanf("%d%d",&nn,&mm),(nn||mm))
56     {
57         n=0;
58         for(int i=0; i<mm; i++)
59         {
60             scanf("%s",po[n].s);
61             for(int j=0; j<nn; j++)
62             {
63                 if(po[n].s[j]=='*')
64                 {
65                     strcpy(po[n+1].s,po[n].s);
66                     po[n].s[j]='0';
67                     po[n+1].s[j]='1';
68                     n++;
69                     break;
70                 }
71             }
72             n++;
73         }
74         sort(po,po+n);
75         mm=0;
76         for(int i=1;i<n;i++)
77         {
78             if(strcmp(po[mm].s,po[i].s)<0)
79                 strcpy(po[++mm].s,po[i].s);
80         }
81         n=mm+1;
82         memset(g,false,sizeof(g));
83         for(int i=0; i<n; i++)
84         {
85             for(int j=0; j<n; j++)
86             {
87                 if(check(po[i].s,po[j].s))
88                     g[i][j]=true;
89             }
90         }
91         mm=maxmatch();
92         printf("%d\n",n-mm+mm/2);
93     }
94     return 0;
95 }