UVa 1663 净化器
https://vjudge.net/problem/UVA-1663
题意:
给m个长度为n的模板串,每个模板串包含字符0,1和最多一个星号"*",其中星号可以匹配0或1。例如,模板01*可以匹配010和011两个串。改写这个模板集合,使得模板的个数最少。
思路:
一个模板只能匹配两个字符串。所以要减少次数的话,我们就要尽量把字符串一一配对,这样每两个字符串都可以用一个模板串来表示。那么这就很明显的是求二分图的最大匹配。下面的代码中因为重复匹配了,所以最后需要除2。
1 #include<iostream> 2 #include<string> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 const int maxn = 2100; 9 int n, m; 10 int c[maxn]; 11 int g[maxn][maxn]; 12 int vis[maxn]; 13 int match[maxn]; 14 15 int dfs(int x) 16 { 17 for (int i = 0; i < maxn; i++) 18 { 19 if (g[x][i] && !vis[i]) 20 { 21 vis[i] = 1; 22 if (match[i] == -1 || dfs(match[i])) 23 { 24 match[i] = x; 25 return 1; 26 } 27 } 28 } 29 return 0; 30 } 31 32 int main() 33 { 34 char s[15]; 35 ios::sync_with_stdio(false); 36 //freopen("D:\\txt.txt", "r", stdin); 37 while (~scanf("%d%d",&n,&m)&&(n||m)) 38 { 39 memset(c, 0, sizeof(c)); 40 memset(g, 0, sizeof(g)); 41 for (int i = 0; i < m; i++) 42 { 43 int num= 0; 44 int pos = -1; 45 scanf("%s", s); 46 for (int j = 0; j < n; j++) 47 { 48 if (s[j] == '1') num |= 1 << j; 49 else if (s[j] == '*') pos = j; 50 } 51 c[num] = 1; 52 if (pos != -1) 53 { 54 num |= 1 << pos; 55 c[num] = 1; 56 } 57 } 58 int cnt = 0; 59 for (int i = 0; i < maxn; i++) 60 { 61 if (c[i]) 62 { 63 cnt++; 64 for (int j = 0; j < n; j++) 65 { 66 int temp = i ^ (1 << j); 67 if (c[temp]) g[i][temp] = 1; 68 } 69 } 70 } 71 int tot = 0; 72 memset(match, -1, sizeof(match)); 73 for (int i = 0; i < maxn; i++) 74 { 75 memset(vis, 0, sizeof(vis)); 76 tot += dfs(i); 77 } 78 cout << cnt - tot / 2 << endl; 79 } 80 }