HDU 4185 Oil Skimming 【最大匹配】

<题目链接>

题目大意:

给你一张图,图中有 '*' , '.' 两点,现在每次覆盖相邻的两个 '#' ,问最多能够覆盖几次。

解题分析:

无向图二分匹配的模板题,每个'#'点与周围四个方向的'#'建立匹配关系,然后用匈牙利跑一遍,因为匹配的两点各会进行相互匹配一次,所以最大匹配数为ans/2。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N=600+10;   //本题数据中'#'数量较少,开到600都能AC 
 7 char mpa[605][605];
 8 int n,vN,vM;
 9 int g[N][N],cnt[605][605],vis[N],match[N];
10 bool dfs(int x){
11     for(int i=1;i<=vM;i++){
12         if(g[x][i]&&!vis[i]){
13             vis[i]=1;
14             if(match[i]==-1||dfs(match[i])){
15                 match[i]=x;
16                 return true;
17             }
18         }
19     }
20     return false;
21 }
22 int Hungary(){
23     int ans=0;
24     memset(match,-1,sizeof(match));
25     for(int i=1;i<=vN;i++){
26         memset(vis,0,sizeof(vis));
27         if(dfs(i))ans++;
28     }
29     return ans;
30 }
31 int main(){
32     int T;scanf("%d",&T);
33     int ncase=0;
34     while(T--){
35         scanf("%d",&n);
36         int pos=0;
37         for(int i=1;i<=n;i++){
38             scanf("%s",mpa[i]+1);
39             for(int j=1;j<=n;j++)
40                 if(mpa[i][j]=='#')cnt[i][j]=++pos;     //给所有的'#'分配编号
41         }
42         memset(g,0,sizeof(g));
43         //将该点与其周围四个方向的'#'都建立匹配关系
44         for(int i=1;i<=n;i++){
45             for(int j=1;j<=n;j++){
46                 if(mpa[i][j]!='#')continue;
47                 if(i-1>=1&&mpa[i-1][j]=='#')g[cnt[i][j]][cnt[i-1][j]]=1;
48                 if(j-1>=1&&mpa[i][j-1]=='#')g[cnt[i][j]][cnt[i][j-1]]=1;
49                 if(i+1<=n&&mpa[i+1][j]=='#')g[cnt[i][j]][cnt[i+1][j]]=1;
50                 if(j+1<=n&&mpa[i][j+1]=='#')g[cnt[i][j]][cnt[i][j+1]]=1;
51             }
52         }
53         vN=vM=pos;
54         int ans=Hungary();   //求出最大匹配数
55         printf("Case %d: %d\n",++ncase,ans/2);    //因为匹配的两点会相互各进行一次匹配,所以这里要除以2
56     }
57     return 0;
58 }

 

 

2018-11-14

posted @ 2018-11-14 18:15  悠悠呦~  阅读(180)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end