二分图最大匹配

 

题目链接:here

 

题解:

BFS+二分图最大匹配。
这题的入手点就是休息点的个数比较小,最多52个。
首先对每个休息点跑一遍BFS,记录休息点到每个点的最短距离。
判断某个金矿是否在两个休息点之间可以被采集到:
例如判断某金矿与BC路径,如果这个金矿与B的最短距离加上这个金矿与C的最短距离等于B与C的最短距离,则代表这个金矿在BC路径上可以被采集到。
然后建二分图,一边是金矿,另一边是路径,如果某个金矿能在某条路径上能被采集到,则建边。
最后跑一次二分图最大匹配,就是答案。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=110;
  4 const int inf=0x3f3f3f3f;
  5 char s[maxn][maxn];
  6 
  7 struct Edge{
  8     int v,nex;
  9 }e[maxn*maxn];
 10 int head[maxn];
 11 int cnt=0;
 12 
 13 void init(){
 14     memset(head,-1,sizeof(head));
 15     cnt=0;
 16 }
 17 void add(int u,int v){
 18     e[cnt].v=v;
 19     e[cnt].nex=head[u];
 20     head[u]=cnt++;
 21 }
 22 int n,m;
 23 int d[66][maxn][maxn];
 24 struct Node{
 25     int x,y;
 26 }a,b;
 27 int vis[maxn][maxn];
 28 int slo[66][66];
 29 
 30 int dir[4][2]={0,1,0,-1,1,0,-1,0};
 31 void bfs(int x,int y,int id){
 32     memset(vis,0,sizeof(vis));
 33     queue<Node> q;
 34     a.x=x;a.y=y;
 35     d[id][x][y]=0;
 36     q.push(a);
 37     vis[x][y]=1;
 38     while(!q.empty()){
 39         a=q.front();
 40         q.pop();
 41         if(id==25&&s[a.x][a.y]=='a') slo[id][id+1]=d[id][a.x][a.y];
 42         else if(id<25&&s[a.x][a.y]-'A'==id+1) slo[id][id+1]=d[id][a.x][a.y];
 43         else if(id>25&&s[a.x][a.y]-'a'+26==id+1) slo[id][id+1]=d[id][a.x][a.y];
 44         for(int i=0;i<4;i++){
 45             b.x=a.x+dir[i][0];
 46             b.y=a.y+dir[i][1];
 47             if(b.x>=0&&b.x<n&&b.y>=0&&b.y<m&&!vis[b.x][b.y]&&s[b.x][b.y]!='#') {
 48                 d[id][b.x][b.y]=d[id][a.x][a.y]+1;
 49                 vis[b.x][b.y]=1;
 50                 q.push(b);
 51             }
 52         }
 53     }
 54 }
 55 int vb[maxn*maxn];
 56 int match[maxn*maxn];
 57 
 58 int Hungary(int u){
 59     for(int i=head[u];~i;i=e[i].nex){
 60         int v=e[i].v;
 61         if(!vb[v]){
 62             vb[v]=1;
 63             if(match[v]==-1||Hungary(match[v])){
 64                 match[v]=u;
 65                 return 1;
 66             }
 67         }
 68     }
 69     return 0;
 70 }
 71 
 72 int main(){
 73     while(scanf("%d%d",&n,&m)!=EOF){
 74         memset(d,inf,sizeof(d));
 75         memset(slo,inf,sizeof(slo));
 76         init();
 77         int st=0;
 78         for(int i=0;i<n;i++) scanf("%s",s[i]);
 79         for(int i=0;i<n;i++){
 80             for(int j=0;j<m;j++){
 81                 if(isupper(s[i][j])) bfs(i,j,s[i][j]-'A'),st++;
 82                 if(islower(s[i][j])) bfs(i,j,s[i][j]-'a'+26),st++;
 83             }
 84         }
 85         int ok = 0;
 86         for(int i=0;i<st-1;i++) if(slo[i][i+1]==inf) {
 87             puts("-1");
 88             ok = 1;
 89             break;
 90         }
 91         if(ok) continue;
 92       //  for(int i=0;i<st;i++) printf("---%d\n",slo[i][i+1]);
 93         /*
 94         int id;
 95         while(scanf("%d",&id)){
 96         for(int i=0;i<n;i++)
 97             for(int j=0;j<m;j++) printf("%d%c",d[id][i][j],j==m-1?'\n':' ');
 98         }
 99         */
100         int gold=0;
101         for(int i=0;i<n;i++){
102             for(int j=0;j<m;j++){
103                 if(s[i][j]=='*'){
104                     for(int k=0;k<st-1;k++){
105                         if(d[k][i][j]+d[k+1][i][j]==slo[k][k+1]){
106                             add(k,gold);
107                         }
108                     }
109                     gold++;
110                 }
111             }
112         }
113         int ans=0;
114         memset(match,-1,sizeof(match));
115         for(int i=0;i<st-1;i++){
116             memset(vb,0,sizeof(vb));
117             if(Hungary(i)) ans++;
118         }
119         printf("%d\n",ans);
120     }
121     return 0;
122 }
View Code

 

posted @ 2017-10-10 23:35  yijiull  阅读(186)  评论(0编辑  收藏  举报