这个题是求给棋盘上的车涂色,使得满足要求。这个题白书上面放的二分图匹配,最开始确实没想到要进行补边操作,很明显的是答案一定是所有点的度的最大值,关键是对不足答案值的点要进行补边,这个是参考别人代码才知道的。
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn=110; const int maxm=maxn*maxn; char map[maxn][maxn]; int e,n,head[maxn],nxt[maxm],pnt[maxm],link[maxn],inrow[maxn],incol[maxn]; int color[maxn][maxn]; bool vis[maxn],del[maxm]; void AddEdge(int u,int v) { pnt[e]=v;nxt[e]=head[u];head[u]=e++; } bool DFS(int u) { for(int i=head[u];i!=-1;i=nxt[i]) { if(!del[i]&&!vis[pnt[i]]) { vis[pnt[i]]=1; if(link[pnt[i]]==-1||DFS(link[pnt[i]])) { link[pnt[i]]=u; return true; } } } return false; } void Build(int colors) { e=0; memset(head,-1,sizeof(head)); memset(del,0,sizeof(del)); for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(map[i][j]=='*') AddEdge(i,j); for(int i=0;i<n;i++) if(inrow[i]<colors) { for(int j=0;j<n&&inrow[i]<colors;j++) if(incol[j]<colors) { while(incol[j]<colors&&inrow[i]<colors) { AddEdge(i,j); incol[j]++; inrow[i]++; } } } } int main() { int T; scanf("%d",&T); while(T--) { memset(color,0,sizeof(color)); memset(inrow,0,sizeof(inrow)); memset(incol,0,sizeof(incol)); scanf("%d",&n); int rook=0; for(int i=0;i<n;i++) { scanf("%s",map[i]); for(int j=0;j<n;j++) if(map[i][j]=='*') { incol[j]++; inrow[i]++; rook=max(rook,inrow[i]); rook=max(rook,incol[j]); } } int col=0; Build(rook); while(col<rook) { col++; memset(link,-1,sizeof(link)); int ans=0; for(int i=0;i<n;i++) { memset(vis,0,sizeof(vis)); if(DFS(i)) ans++; } for(int i=0;i<n;i++) { if(map[link[i]][i]=='*') color[link[i]][i]=col; for(int j=head[link[i]];j!=-1;j=nxt[j]) if(!del[j]&&pnt[j]==i) { del[j]=1; break; } } } printf("%d\n",col); for(int i=0;i<n;i++) for(int j=0;j<n;j++) printf("%d%c",color[i][j],j==n-1?'\n':' '); } return 0; }