Uva-10615-Rooks

150 篇文章 0 订阅

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

代码:

#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值