【網路流】【二分圖多重匹配】【Hungary演算法】HDU 3605 Escape
阿新 • • 發佈:2019-01-04
【大意】有n個人和m個星球,每個人有想去的星球,星球有最大容納量,問能否給所有的人都安排上?
【思路】本來是最大流的題..但是n太大了,會T,看部落格說要用狀壓...就學了一波匈牙利演算法求二分圖最大匹配...狀壓的寫法有空補一補...
就是讓每一個男的直接匹配他清單上第一個女的,如果第一個被人匹配了,就去讓那個男的找他的下一個女的,如果找到了,新來的男的就和這個女的匹配,否則這個男的就找下一個女的。
【二分圖多重匹配】多重匹配就是女的可以找好幾個老公,有上限。就把上面的改成:如果這個女的男票數量沒有達到上上限,就直接匹配,否則嘗試擠掉每一個她的男友,成功就匹配,失敗就找下一個女的。
【匈牙利演算法的程式碼】
//虛擬碼 bool dfs(int u)//尋找從u出發的增廣路徑 { for each v∈u的鄰接點 if(v未訪問){ 標記v已訪問; if(v未匹配||dfs(cy[v])){ cx[u]=v; cy[v]=u; return true;//有從u出發的增廣路徑 } } return false;//無法找到從u出發的增廣路徑 } //程式碼 bool dfs(int u){ for(int v=1;v<=m;v++) if(t[u][v]&&!vis[v]){ vis[v]=1; if(cy[v]==-1||dfs(cy[v])){ cx[u]=v;cy[v]=u; return 1; } } return 0; } void maxmatch()//匈牙利演算法主函式 { int ans=0; memset(cx,0xff,sizeof cx); memset(cy,0xff,sizeof cy); for(int i=0;i<=nx;i++) if(cx[i]==-1)//如果i未匹配 { memset(visit,false,sizeof(visit)) ; ans += dfs(i); } return ans ; }
【程式碼】
#include<cstdio> #include<cstring> const int Mn=100005; const int Mm=15; int mp[Mn][Mm]; int volume[Mm];//每個星球的容量 int n,m; int ymatch[Mm][Mn];//ymatch[哪個星球][星上第幾個人]=是誰 int cnt[Mn];//cnt[哪個星球]=已經住了多少人 bool vis[Mm]; bool dfs(int x)///僅僅是找x有沒有能娶的 { for(int i=0; i<m; i++) { if(vis[i]) continue; if(mp[x][i]==0) continue; vis[i]=1; if(cnt[i]<volume[i])//如果還能加人 { ymatch[i][cnt[i]]=x; cnt[i]++; return 1; } else { for(int j=0; j<cnt[i]; j++) { if(dfs(ymatch[i][j])) //如果本來配完的這個人還能去別的地方 { ymatch[i][j]=x; return 1; } } } } return 0; } void hungary() { for(int i=0; i<n; i++) { memset(vis,0,sizeof(vis)); if(dfs(i)==0) { printf("NO\n");//只要有一個人不能匹配就no return; } } printf("YES\n"); return; } int main() { while(~scanf("%d%d",&n,&m)) { memset(cnt,0,sizeof(cnt)); memset(mp,0,sizeof(mp)); for(int i=0; i<n; i++) { for(int j=0; j<m; j++) { int t; scanf("%d",&t); mp[i][j]=t; } } for(int i=0; i<m; i++) scanf("%d",&volume[i]); hungary(); } }