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;
}
posted @ 2016-09-11 10:14  cycleke  阅读(122)  评论(0编辑  收藏  举报