Uva 10615 Rooks(二分圖完美匹配+補邊)
阿新 • • 發佈:2019-02-04
思路:
1.給棋子染色,要求每行每列棋子顏色均不相同。
2.構造二分圖模型,左右各n個點,若第i行第j列存在棋子,則由左邊第i個點向右邊第j個點連邊。則問題變為給邊染色,使得每個點所連邊顏色均不相同。
3.對於二分圖中每個點,若存在一完美匹配,則所有匹配邊無衝突,可染同一色,設需要使用ans種顏色,則可求ans次完美匹配。
4.由於每點度數可能不相同,完美匹配不一定存在,若最大匹配不是完美匹配,則有可能造成ans次匹配後存在邊為染色,所以應新增多餘的邊,使得每次求出的匹配為最大匹配。
5.設所有點的最大度數為k,則所需顏色數至少為k。
5.若左邊一點的所連邊數小於k,則尋找右邊所連邊數小於k的點,連邊,直到左邊所有點所連邊數等於k。則該二分圖為k階正則二分圖(每點的度數均為k),由定理可知k階正則二分圖必存在完美匹配,則找到該組匹配後,從圖中刪去匹配邊,二分圖變為k-1階正則二分圖,一直處理,知道所有邊都匹配為止。由此,ans=k。補邊後求k次完美匹配即可。
#include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define debug using namespace std; const int maxn=100+50; int n,ans; int vis[maxn]; char ch[maxn][maxn]; vector<int> g[maxn]; int ansG[maxn][maxn]; int rt[maxn],lt[maxn]; int cnt1[maxn],cnt2[maxn]; int match(int u) { for(int i=0; i<g[u].size(); i++) { int nt=g[u][i]; if(!vis[nt]) { vis[nt]=1; if(rt[nt]==-1||match(rt[nt])) { rt[nt]=u; lt[u]=nt; return 1; } } } return 0; } void hungary() { memset(rt,-1,sizeof(rt)); for(int i=1; i<=n; i++) { memset(vis,0,sizeof(vis)); match(i); } } void init() { ans=0; memset(cnt1,0,sizeof(cnt1)); memset(cnt2,0,sizeof(cnt2)); memset(ansG,0,sizeof(ansG)); for(int i=0; i<=n; i++) g[i].clear(); } void solve() { for(int i=1; i<=ans; i++) { hungary(); for(int j=1; j<=n; j++) { if(ch[j][lt[j]]=='*') { //cout<<j<<" "<<lt[j]<<endl; ansG[j][lt[j]]=i; } for(int k=0; k<g[j].size(); k++) { if(g[j][k]==lt[j]) { // cout<<"* "<<j<<" "<<lt[j]<<" "<<g[j][k]<<endl; g[j].erase(g[j].begin()+k); break; } } } } } void build() { for(int i=1; i<=n; i++) { ans=max(ans,max(cnt1[i],cnt2[i])); } for(int i=1; i<=n; i++) { for(int j=1; j<=n&&cnt1[i]<ans; j++) { while(cnt1[i]<ans&&cnt2[j]<ans) { cnt1[i]++,cnt2[j]++; g[i].push_back(j); } } } } int main() { #ifdef debu freopen("in.txt","r",stdin); #endif // debug int t; scanf("%d",&t); while(t--) { scanf("%d",&n); init(); for(int i=1; i<=n; i++) { getchar(); for(int j=1; j<=n; j++) { scanf("%c",&ch[i][j]); if(ch[i][j]=='*') { cnt1[i]++,cnt2[j]++; g[i].push_back(j); } } } build(); solve(); printf("%d\n",ans); for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(j==1) printf("%d",ansG[i][j]); else printf(" %d",ansG[i][j]); } printf("\n"); } } return 0; }