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; } 
           
          
         
        
       
      
    
 
   

你可能感兴趣的:(mac)