二分图最大匹配
Posted yijiull
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分图最大匹配相关的知识,希望对你有一定的参考价值。
题目链接: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 }
以上是关于二分图最大匹配的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1854: [Scoi2010]游戏 (并查集||二分图最大匹配)