HDU 3360 National Treasures(最小点覆盖)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3360

题目大意:

在一个n*m的格子中,每个格子有一个数值,-1表示空,其余表示财宝。每个财宝的数值转换成二进制数,
12个二进制位上数值,从右到左,第i个位是1表示图上相应第i序号位置需要有警卫。所有的要求位置有警卫财宝才安全。
财宝可以被警卫替换。问至少需要替换多少财宝才能保证所有财宝的安全。

解题思路:

需要警戒位置是财宝的讯号对财宝位置讯号建边。由于警戒位置与财宝位置的横纵坐标奇偶相反,可以建得二分图。
对于所建图,根据题意就是找出最少的顶点使得剩余顶点覆盖所有的边,即最小顶点覆盖数为答案。

代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<vector>
 5 #include<queue>
 6 #include<algorithm>
 7 using namespace std;
 8 const int N=1e2+5;
 9 vector<int>v[N*N];
10 
11 int n,m,xN,yN;
12 int link[N*N],num[N][N],mp[N][N];
13 bool vis[N*N];
14 int dir[][2] = {{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,0},{0,1},{1,0},{0,-1}};
15 
16 bool dfs(int u){
17     for(int i=0;i<v[u].size();i++){
18         int t=v[u][i];
19         if(!vis[t]){
20             vis[t]=true;
21             if(link[t]==-1||dfs(link[t])){
22                 link[t]=u;
23                 return true;
24             }
25         }
26     }
27     return false;
28 }
29 
30 int max_match(){
31     memset(link,-1,sizeof(link));
32     int ans=0;
33     for(int i=1;i<=xN;i++){
34         memset(vis,false,sizeof(vis));
35         if(dfs(i)) ans++;
36     }
37     return ans;
38 }
39 
40 
41 bool check(int x,int y){
42     if(x<=0||y<=0||x>n||y>m||mp[x][y]==-1) return false;
43     return true;
44 }
45 
46  void init(){
47     xN=yN=0;
48     for(int i=0;i<=n*m;i++) v[i].clear();
49  }
50 
51 int main(){
52     int cas=0;
53     while(~scanf("%d%d",&n,&m)&&n&&m){
54         init();
55         for(int i=1;i<=n;i++){
56             for(int j=1;j<=m;j++){
57                 if((i+j)%2==0) num[i][j]=++xN;
58                 else num[i][j]=++yN;
59             }
60         }
61         for(int i=1;i<=n;i++){
62             for(int j=1;j<=m;j++){
63                 scanf("%d",&mp[i][j]);
64             }
65         }
66         for(int i=1;i<=n;i++){
67             for(int j=1;j<=m;j++){
68                 if(mp[i][j]==-1) continue;
69                 for(int k=0;k<12;k++){
70                     if(mp[i][j]&(1<<k)){
71                         int x=i+dir[k][0];
72                         int y=j+dir[k][1];
73                         if(!check(x,y)) continue;
74                         if((i+j)%2==0) v[num[i][j]].push_back(num[x][y]);
75                         else v[num[x][y]].push_back(num[i][j]);
76                     }
77                 }
78             }
79         }
80         printf("%d. %d\n",++cas,max_match());
81     }
82     return 0;
83 }

 

posted @ 2018-04-11 00:22  Yeader  阅读(235)  评论(0编辑  收藏  举报