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 }

 

转载于:https://www.cnblogs.com/zyb993963526/p/6516893.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值