这个题是求给棋盘上的车涂色,使得满足要求。这个题白书上面放的二分图匹配,最开始确实没想到要进行补边操作,很明显的是答案一定是所有点的度的最大值,关键是对不足答案值的点要进行补边,这个是参考别人代码才知道的。
代码:
#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;
}