模版集合个数减少是因为匹配串集合中没被匹配过的一对串匹配了。所以就是找一个二分图最大匹配。
因为集合X和Y是不好分开的,但是可以直接跑,两个集合都会跑一遍,所以一个匹配会被算两次,返回的时候除以2就行了。
也有另外一种写法不用除以2的。
#include<bits/stdc++.h> using namespace std; const int maxn = 10; const int N = 1<<maxn; #define debug(x) bitset<16> bs(x); cout<<bs<<endl; bool vis[N]; int match[N]; int dfsT[N], dfsTime, n, m, M,tot; bool dfs(int u) { for(int i = 0; i < n; i++){ int v = u^(1<<i); if(vis[v] && dfsT[v] != dfsTime){ dfsT[v] = dfsTime; if(!~match[v] || dfs(match[v])){ match[v] = u; return true; } } } return false; } int MaxMatch() { memset(match,-1,sizeof(int)*M); memset(dfsT,0,sizeof(int)*M); dfsTime = 0; int ans = 0; for(int i = 0; i < M; i++){ if(vis[i]){ dfsTime++; if(dfs(i)) ans++; } } return ans>>1; } int read() { M = 1<<n; memset(vis,0,sizeof(bool)*M); for(int i = 0; i < m; i++){ int fg = -1,t = 0; scanf(" "); char ch; for(int j = 0;j < n; j++){ ch = getchar(); if(ch == '*') fg = j; if(ch != '0') t |= 1<<j; } vis[t] = true; if(~fg) vis[t^(1<<fg)] = true; } int ret = 0; for(int i = 0; i < M; i++) if(vis[i]) ret++; return ret; } int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&m),n){ printf("%d ",read()-MaxMatch()); } return 0; }