Poj--2724(最小边覆盖)

2014-11-05 22:30:47

思路:首先把所有感染的cheeses存到一个数组,注意要去重!!(QAQ坑了两发)然后给每对满足条件:二进制只有一位不同的两个点建边,因为这些点对可以通过一次操作搞定,

为了覆盖所有点,要选一些边,就是最小边覆盖问题了。判断两个数是否只有一位不同:设两数为A、B,且C=A^B,若(C && (C & (C - 1))) == 0那么满足条件,思考。

  1 /*************************************************************************
  2     > File Name: 2724.cpp
  3     > Author: Nature
  4     > Mail: 564374850@qq.com 
  5     > Created Time: Wed 05 Nov 2014 08:57:02 PM CST
  6 ************************************************************************/
  7 
  8 #include <cstdio>
  9 #include <cstring>
 10 #include <cstdlib>
 11 #include <cmath>
 12 #include <vector>
 13 #include <map>
 14 #include <set>
 15 #include <stack>
 16 #include <queue>
 17 #include <iostream>
 18 #include <algorithm>
 19 using namespace std;
 20 #define lp (p << 1)
 21 #define rp (p << 1|1)
 22 #define getmid(l,r) (l + (r - l) / 2)
 23 #define MP(a,b) make_pair(a,b)
 24 typedef long long ll;
 25 const int INF = 1 << 30;
 26 const int maxn = 2010;
 27 
 28 char s[20];
 29 int N,M,cnt;
 30 int first[maxn],next[maxn * maxn],ver[maxn * maxn],ecnt;
 31 int used[maxn],mat[maxn];
 32 int num[maxn];
 33 
 34 void Init(){
 35     memset(first,-1,sizeof(first));
 36     ecnt = cnt = 0;
 37 }
 38 
 39 void Add_edge(int u,int v){
 40     next[++ecnt] = first[u];
 41     ver[ecnt] = v;
 42     first[u] = ecnt;
 43 }
 44 
 45 void Build_graph(){
 46     int c;
 47     for(int i = 1; i <= cnt; ++i){
 48         for(int j = i + 1; j <= cnt; ++j){
 49             c = num[i] ^ num[j];
 50             if((c && (c & (c - 1))) == 0){
 51                 Add_edge(i,j);
 52                 Add_edge(j,i);
 53             }
 54         }
 55     }
 56 }
 57 
 58 bool find(int p){
 59     for(int i = first[p]; i != -1; i = next[i]){
 60         int v = ver[i];
 61         if(used[v] == 0){
 62             used[v] = 1;
 63             if(mat[v] == 0 || find(mat[v])){
 64                 mat[v] = p;
 65                 return true;
 66             }
 67         }
 68     }
 69     return false;
 70 }
 71 
 72 int Hungary(){
 73     int ans = 0;
 74     memset(mat,0,sizeof(mat));
 75     for(int i = 1; i <= cnt; ++i){
 76         memset(used,0,sizeof(used));
 77         if(find(i)) ++ans;
 78     }
 79     return ans;
 80 }
 81 
 82 int main(){
 83     while(scanf("%d%d",&N,&M) != EOF){
 84         if(N == 0 && M == 0)
 85             break;
 86         Init();
 87         while(M--){
 88             scanf("%s",s);
 89             int val1 = 0,val2 = 0,fac = 1,flag = 0;
 90             for(int i = N - 1; i >= 0; --i){
 91                 if(s[i] == '*'){
 92                     val2 = val1;
 93                     val1 += fac;
 94                     flag = 1;
 95                 }
 96                 else if(s[i] == '1'){
 97                     val1 += fac;
 98                     if(flag) val2 += fac;
 99                 }
100                 fac <<= 1;
101             }
102             num[++cnt] = val1;
103             if(flag) num[++cnt] = val2;
104         }
105         sort(num + 1,num + cnt + 1);
106         cnt = unique(num + 1,num + cnt + 1) - num - 1;
107         Build_graph();
108         printf("%d\n",cnt - Hungary() / 2);
109     }
110     return 0;
111 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4077517.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值