1. 程式人生 > >二分圖最大匹配

二分圖最大匹配

個數 c++ 最大匹配 images include scan open 匹配 比較

題目鏈接: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

二分圖最大匹配