二分圖 km演算法模板
阿新 • • 發佈:2018-11-16
參考連結:https://blog.csdn.net/sixdaycoder/article/details/47720471
https://www.cnblogs.com/Lanly/p/6291214.html
https://www.cnblogs.com/Mychael/p/8994980.html
題目:hdu 2255
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define INF 0x3f3f3f3f const int maxn=305; int match[maxn],lx[maxn],ly[maxn],slack[maxn]; int G[maxn][maxn]; bool visx[maxn],visy[maxn]; int n,nx,ny; bool findpath(int x) { int tempdelta; visx[x]=1; for(int y=0;y<ny;y++) { if(visy[y]) continue; tempdelta=lx[x]+ly[y]-G[x][y]; if(tempdelta==0){ visy[y]=1; if(match[y]==-1||findpath(match[y])){ match[y]=x; return true; } } else if(slack[y]>tempdelta) slack[y]=tempdelta; } return false; } void KM() { for(int x=0;x<nx;x++) { for(int j=0;j<ny;j++) slack[j]=INF; while(1) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(findpath(x)) break; int delta=INF; for(int j=0;j<ny;j++) if(!visy[j]) delta=min(delta,slack[j]); for(int i=0;i<nx;i++) { if(visx[i]) lx[i]-=delta; ///已匹配點處理 if(visy[i]) ly[i]+=delta; else slack[i]-=delta; } } } } void solve() { memset(match,-1,sizeof(match)); memset(ly,0,sizeof(match)); for(int i=0;i<nx;i++) { lx[i]=-INF; for(int j=0;j<ny;j++) lx[i]=max(lx[i],G[i][j]); } KM(); } int main() { while(~scanf("%d",&n)) { nx=ny=n; for(int i=0;i<nx;i++) for(int j=0;j<ny;j++) scanf("%d",&G[i][j]); solve(); int ans=0; for(int i=0;i<ny;i++) { if(match[i]!=-1) ans+=G[match[i]][i]; } printf("%d\n",ans); } }
題目:hdu 1533
題意:給幅圖,有相同的人和相同的房子,讓你把每個人移動到房子裡,每移動一個單位,要出一塊錢,問你:將所有人移動到房子裡,最少移動步數是多少?
題解:直接建個二分圖。
///題目要的是最短路,所以我們把值取負,就相當於km演算法求了 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define INF 0x3f3f3f3f const int maxn=110; char op[maxn][maxn]; int match[maxn],lx[maxn],ly[maxn],slack[maxn]; bool visx[maxn],visy[maxn]; struct node{ int x,y; node(){} node(int _x,int _y){ x=_x;y=_y; } }house[maxn],people[maxn]; ///儲存房子,人的位置 int G[maxn][maxn],nx,ny; bool findpath(int x) { int tempdelta; visx[x]=1; for(int y=0;y<ny;y++) { if(visy[y]) continue; tempdelta=lx[x]+ly[y]-G[x][y]; if(tempdelta==0) { visy[y]=1; if(match[y]==-1||findpath(match[y])){ match[y]=x; return 1; } } else if(slack[y]>tempdelta) slack[y]=tempdelta; } return false; } void KM() { for(int x=0;x<nx;x++) { // printf("asdf"); for(int j=0;j<ny;j++) slack[j]=INF; while(1) { // printf("tiao"); memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(findpath(x)) break; int delta=INF; for(int j=0;j<ny;j++) if(!visy[j]) delta=min(delta,slack[j]); for(int i=0;i<nx;i++) if(visx[i]) lx[i]-=delta; for(int j=0;j<ny;j++) { if(visy[j]) ly[j]+=delta; else slack[j]-=delta; } } } } void solve() ///模板了 { memset(match,-1,sizeof(match)); memset(ly,0,sizeof(ly)); for(int i=0;i<nx;i++) { lx[i]=-INF; for(int j=0;j<ny;j++) lx[i]=max(lx[i],G[i][j]); } KM(); } int main() { int n,m; while(scanf("%d%d",&n,&m)) { if(m==0&&n==0) break; for(int i=0;i<n;i++) scanf("%s",op[i]); nx=ny=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++){ if(op[i][j]=='m') people[nx++]=node(i,j); ///儲存點 else if(op[i][j]=='H') house[ny++]=node(i,j); } memset(G,0,sizeof(G)); for(int i=0;i<nx;i++) { for(int j=0;j<ny;j++) ///建圖 { G[i][j]=-(abs(house[j].x-people[i].x)+abs(house[j].y-people[i].y)); } } solve(); int ans=0; for(int i=0;i<ny;i++) { if(match[i]!=-1) ans+=G[match[i]][i]; } printf("%d\n",-ans); } return 0; }