poj 2724 Purifying Machinef
poj 2724 Purifying Machinef
题意
每一个01串中最多含有一个'*','*'既可表示0也可表示1,给出一些等长的这样的01串, 问最少能用多少个这样的串表示出这些串。如:000、010、0*1表示000、010、001、011,最 少只需用00*、01*这两个即可表示出来。
题解
很明显,在可以用'*'时,就应该多用'*'。我们可以将每个字符的每一位都变为'*'进行匹配, 用总数减去匹配数就是答案。不过由于每个01串都被作为匹配串和被匹配串,所以匹配数要除2。
#include <cstdio>
#include <cstring>
const int N = 1024;
int vis[N], vist[N], Tim, SearchTime, link[N], n, m, MS;
bool dfs(int u) {
for (int i = 0, t; i < n; ++i) {
t = u ^ (1<<i);
if (!(vis[t] ^ Tim) && (vist[t] ^ SearchTime)) {
vist[t] = SearchTime;
if (!~link[t] || dfs(link[t])) return link[t] = u, true;
}
}
return false;
}
int main() {
int tot, match, pos, t, i; char ch;
while (scanf("%d%d", &n, &m) ^ EOF) {
if (!n && !m) break;
++Tim; MS = 1 << n; tot = match = 0;
while (m--) {
t = 0; pos = -1; getchar();
for (i=0;i<n;++i) ch = getchar(), (ch^'*')?1:pos=i, (ch^'0')?t|=1<<i:1;
vis[t] = Tim; if (~pos) vis[t^(1<<pos)] = Tim;
}
for (i = 0; i < MS; ++i) tot += vis[i] == Tim;
memset(link, -1, sizeof link);
for (i = 0; i < MS; ++i) if (vis[i] == Tim && (++SearchTime, dfs(i))) ++match;
match >>= 1;
printf("%d\n", tot - match);
}
return 0;
}