POJ 2724 Purifying Machine (二分图匹配)

题意

给定m个长度为n的01串(*既表示0 or 1。如*01表示001和101)。现在要把这些串都删除掉,删除的方法是:①一次删除任意指定的一个;②如果有两个串仅有一个字符不同,则可以同时删除这两个。求最少要多少次可以删完,并且同一个串不能删两次。

思路

我们用点表示一个串,如果两个串之间只有一个字符不同,那么这两个串之间连接一条,最大匹配数就是节省的次数。 因为每个串中的1为奇数的串之间是不能匹配的(不可能只有1个不同),同理,偶数也是。所以,可以按照1的奇偶性把数据分成2份,所以是一个二分图匹配。然后答案就是所有串数 - 最大匹配数。

代码

 
#include 
#include 
#include 
#include 
#include 
#include 
#define MID(x,y) ((x+y)/2)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXV = 2005;                   //N1+N2
vector  adj[MAXV];
struct MaximumMatchingOfBipartiteGraph{
    int vn;
    void init(int n){                   //二分图两点集点的个数
        vn = n;
        for (int i = 0; i <= vn; i ++)     adj[i].clear();
    }
    void add_uedge(int u, int v){
		adj[u].push_back(v);
		adj[v].push_back(u);
    }
    bool vis[MAXV];
    int mat[MAXV];                      //记录已匹配点的对应点
    bool cross_path(int u){
        for (int i = 0; i < (int)adj[u].size(); i ++){
            int v = adj[u][i];
            if (!vis[v]){
                vis[v] = true;
                if (mat[v] == 0 || cross_path(mat[v])){
                    mat[v] = u;
                    mat[u] = v;
                    return true;
                }
            }
        }
        return false;
    }
    int hungary(){
        mem(mat, 0);
        int match_num = 0;
        for (int i = 1; i <= vn; i ++){
            mem(vis, 0);
            if (!mat[i] && cross_path(i)){
                match_num ++;
            }
        }
        return match_num;
    }
	void print_edge(){
        for (int i = 1; i <= vn; i ++){
            for (int j = 0; j < (int)adj[i].size(); j ++){
                printf("u = %d v = %d\n", i, adj[i][j]);
            }
        }
    }
}match;

vector  s;
int main(){
	//freopen("test.in", "r", stdin);
	//freopen("test.out", "w", stdout);
	int n, m;
	while(scanf("%d %d", &n, &m), n+m){
        getchar();
        s.clear();
        for (int i = 1; i <= m; i ++){
            char tmps[15];
            scanf("%s", tmps);
            int star = -1;
            for (int j = 0; j < n; j ++){
                if (tmps[j] == '*'){
                    star = j;
                    break;
                }
            }
            if (star == -1){
                if (find(s.begin(), s.end(), tmps) == s.end())
                    s.push_back(string(tmps));
            }
            else{
                tmps[star] = '0';
                if (find(s.begin(), s.end(), tmps) == s.end())
                    s.push_back(string(tmps));
                tmps[star] = '1';
                if (find(s.begin(), s.end(), tmps) == s.end())
                    s.push_back(string(tmps));
            }
        }
        match.init(s.size());
        for (int i = 0; i < s.size(); i ++){
            for (int j = 0; j < i; j ++){
                int dif = 0;
                for (int k = 0; k < n; k ++){
                    if (s[i][k] != s[j][k]){
                        dif ++;
                        if (dif > 1)
                            break;
                    }
                }
                if (dif == 1){
                    match.add_uedge(j+1, i+1);
                }
            }
        }
        printf("%d\n", s.size() - match.hungary());
	}
	return 0;
}
posted @ 2013-08-03 14:00  AbandonZHANG  阅读(126)  评论(0编辑  收藏  举报