二分圖——匈牙利演算法
阿新 • • 發佈:2018-11-16
匈牙利演算法參考連結:
https://blog.csdn.net/sixdaycoder/article/details/47680831
https://www.renfei.org/blog/bipartite-matching.html
題目一:
題意:
一共有N個學生跟P門課程,一個學生可以任意選一 門或多門課,問是否達成:
1.每個學生選的都是不同的課(即不能有兩個學生選同一門課)
2.每門課都有一個代表(即P門課都被成功選過)
輸入為:
第一行一個T代表T組資料
P N(P課程數, N學生數)
接著P行:
第幾行代表第幾門課程,首先是一個數字k代表對這門課程感興趣的同學的個數,接下來是k個對這門課程感興趣同學的編號。
題解:直接建個二分圖搞定。
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<queue> using namespace std; const int maxn=310; vector<int> G[maxn]; int match[maxn]; bool check[maxn]; bool dfs(int u) { for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(!check[v]){ check[v]=true; if(match[v]==-1||dfs(match[v])){ match[v]=u; ///學生匹配課程 return true; } } } return false; } int hungarian(int num_left) { int ans=0; memset(match,-1,sizeof(match)); for(int u=0;u<num_left;u++) { memset(check,0,sizeof(check)); if(dfs(u)) ans++; } return ans; } int main() { int ncase; scanf("%d",&ncase); while(ncase--) { int p,n; scanf("%d%d",&p,&n); for(int i=0;i<p;i++) ///課程 { G[i].clear(); int counts,x; scanf("%d",&counts); while(counts--) { scanf("%d",&x); G[i].push_back(x); ///課程i被學生x所喜歡 } } int ans=hungarian(p); // printf("ans=%d\n",ans); if(p-ans==0) puts("YES"); else puts("NO"); } return 0; }
題目二:
參考連結:https://blog.csdn.net/wchhlbt/article/details/76687002
https://www.2cto.com/kf/201308/233630.html
題意:見連結。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=51; char op[maxn][maxn]; int x[maxn][maxn],y[maxn][maxn]; int maps[maxn*maxn][maxn*maxn]; bool vis[maxn*maxn]; int cx[maxn*maxn],cy[maxn*maxn]; int xpiece,ypiece; int dfs(int u) { for(int v=1;v<=ypiece;v++) { if(maps[u][v]&&!vis[v]){ vis[v]=1; if(cy[v]==-1||dfs(cy[v])) { cy[v]=u; return 1; } } } return 0; } int hungarian() { memset(cy,-1,sizeof(cy)); int res=0; for(int i=1;i<=xpiece;i++) { memset(vis,0,sizeof(vis)); res+=dfs(i); } return res; } int main() { int ncase; scanf("%d",&ncase); int T=0; while(ncase--) { int m,n; scanf("%d%d",&m,&n); for(int i=0;i<m;i++) scanf("%s",op[i]); bool flag; memset(x,0,sizeof(x)); ///初始化 memset(y,0,sizeof(y)); memset(maps,0,sizeof(maps)); xpiece=ypiece=0; for(int i=0;i<m;i++) ///對橫向分塊 { flag=true; for(int j=0;j<n;j++){ if(op[i][j]=='o'){ if(flag) x[i][j]=++xpiece,flag=false; else x[i][j]=xpiece; } else if(op[i][j]=='#') flag=true; } } for(int j=0;j<n;j++) ///對縱向分塊 { flag=true; for(int i=0;i<m;i++){ if(op[i][j]=='o'){ if(flag) y[i][j]=++ypiece,flag=false; else y[i][j]=ypiece; } else if(op[i][j]=='#') flag=true; } } for(int i=0;i<m;i++) ///建圖 { for(int j=0;j<n;j++) { if(x[i][j]) { maps[x[i][j]][y[i][j]]=1; } } } int sum=hungarian(); printf("Case :%d\n%d\n",++T,sum); } }