「刷題筆記」二分圖匹配
阿新 • • 發佈:2020-07-26
板子
兩種寫法:(核心思想是一樣的,使用時實測並沒有什麼區別
兩個引數版(洛谷題解
bool dfs(ll u,ll ti)
{
if(vis[u]==ti)return 0;
vis[u]=ti;
for(int i=head[u];i;i=next[i])
{
if(mh[e[i].v]==0||dfs(mh[e[i].v],ti))
{
mh[e[i].v]=u;
return 1;
}
}
return 0;
}
一個引數版(網上題解多用
bool find(int u) { for(int i=head[u];i;i=next[i]) { int v=e[i].v; if(!vis[v]) { vis[v]=1; if(mh[v]==0||find(mh[v])) { mh[v]=u; return 1; } } } return 0; }
特別注意:使用一個引數版時,每次使用前vis陣列都要清零!
超級英雄Hero
啊這,這不是板子嗎?
然後就因為不讀題+2了。
建圖:錦囊妙計編號是一邊,題目編號是一邊,從錦囊向題目連邊,然後跑匈牙利
注意題意:只有通過一題才能繼續答題,所以如果中途斷了直接跳出
另外:二分圖有重邊似乎對匈牙利演算法並沒有影響
文理分班
首先建圖,考慮到分班前後座位的變化,我們可以用前後座位建圖,如果之前坐在\(a\)處的同學分班後有可能坐到\(b\)處,則從\(a\)向\(b\)連邊。
同時注意,如果一個人是本班的,且不調班,那他是可以不換座位的,這樣我們就直接從他的座位\(a\)向\(a\)連邊
那麼只要最後每個人都有座位坐就是可行的方案
所以建圖完了以後我們跑二分圖匹配,如果全都能夠匹配則可行
放置機器人
建圖過程很有意思的一道題~
可以分別考慮每一行,每一列,並將每行每列以牆分隔成幾個小部分,那麼顯然,每一個小部分中是隻能放置一個機器人的。
我們又知道給定的行列資訊能確定唯一位置,分隔後同樣如此。我們可以把所有空地 按行分割所屬部分 的編號向它們 按列分割所屬部分 的編號連邊,那麼每一條邊都代表了一個可放置機器人的位置,在得到的這個二分圖上跑匈牙利,那麼最大匹配邊數即為最大能放置的機器人數。
挺有意思的,放下程式碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define ZZ_zuozhe int main() #define N 55 #define E 2550 struct edge { ll u,v; }e[E]; ll tot,head[E],next[E]; void add(ll a,ll b) { ++tot; e[tot].u=a; e[tot].v=b; next[tot]=head[a]; head[a]=tot; } ll T; ll n,m; ll tmp,xcn,ycn,xt; ll kd[N][N],xnm[N][N],ynm[N][N]; ll in(ll &a) { char ch=getchar(); if(ch=='#')return a=0; else if(ch=='o')return a=1; else if(ch=='*')return a=2; } ll vis[E],mh[E]; bool find(ll u) { for(int i=head[u];i;i=next[i]) { ll v=e[i].v; if(!vis[v]) { vis[v]=1; if(mh[v]==0||find(mh[v])) { mh[v]=u; return 1; } } } return 0; } ll ans; ZZ_zuozhe { memset(e,0,sizeof e); memset(kd,0,sizeof kd); memset(xnm,0,sizeof xnm); memset(ynm,0,sizeof ynm); memset(mh,0,sizeof mh); tmp=xt=ans=0; xcn=ycn=1; scanf("%lld%lld",&n,&m); getchar(); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { in(kd[i][j]); // cout<<kd[i][j]<<' '; if(j==1&&tmp==1)tmp=0,xcn++; if(kd[i][j]==1)xnm[i][j]=xcn,tmp=1,xt=xcn; if(kd[i][j]==0&&tmp==1)tmp=0,xcn++; } getchar(); } tmp=0; for(int i=1;i<=m;i++)for(int j=1;j<=n;j++) { if(j==1&&tmp==1)tmp=0,ycn++; if(kd[j][i]==1)ynm[j][i]=ycn,tmp=1; if(kd[j][i]==0&&tmp==1)tmp=0,ycn++; } for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) { add(xnm[i][j],ynm[i][j]); } for(int i=1;i<=xt;i++) { memset(vis,0,sizeof vis); if(find(i))ans++; } // cout<<xcn<<' '<<ycn<<' '<<xt<<endl; printf("%lld\n",ans); return 0; }
貓和狗
運用了最大獨立集的思想
關於最大獨立集什麼的:這篇部落格寫的超超超超詳細啊qaq
明確了定義,我們來看題。