UVA-10615 Rooks (二分图匹配)

题目大意:在一个nxn的方格中,有些位置有车,要给每一个车都涂上颜色,使得同一行和同一列的任意两个车颜色不同,求一种需要颜色种数最少的涂色方案。

题目分析:所需的最少颜色种数是显然就能得出的,假设最少颜色种数为k。如果位置(i,j)是车,那么连一条边i->j,得到一张二分图,进行k次匹配即可构造出解。

 

AC代码:

# include<iostream>
# include<cstdio>
# include<vector>
# include<cstring>
# include<algorithm>
using namespace std;
# define REP(i,s,n) for(int i=s;i<n;++i)
# define CL(a,b) memset(a,b,sizeof(a))
# define CLL(a,b,n) fill(a,a+n,b)

const int N=105;
int inr[N],inc[N],vis[N],link[N],ans[N][N],n;
char p[N][N];
vector<int>G[N];

bool dfs(int x)
{
    REP(i,0,G[x].size()){
        int y=G[x][i];
        if(vis[y]) continue;
        vis[y]=1;
        if(link[y]==-1||dfs(link[y])){
            link[y]=x;
            return true;
        }
    }
    return false;
}

void match()
{
    CL(link,-1);
    REP(i,0,n){
        CL(vis,0);
        dfs(i);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        REP(i,0,n) G[i].clear();
        REP(i,0,n) scanf("%s",p[i]);
        CL(inr,0);
        CL(inc,0);
        REP(i,0,n) REP(j,0,n) if(p[i][j]=='*'){
            ++inr[i];
            ++inc[j];
            G[i].push_back(j);
        }

        int maxn=0;
        REP(i,0,n) maxn=max(maxn,max(inr[i],inc[i]));

        REP(i,0,n) if(inr[i]<maxn){
            for(int j=0;j<n&&inr[i]<maxn;++j){
                while(inr[i]<maxn&&inc[j]<maxn){
                    ++inr[i];
                    ++inc[j];
                    G[i].push_back(j);
                }
            }
        }

        CL(ans,0);
        REP(k,1,maxn+1){
            match();
            REP(i,0,n){
                int r=link[i];
                if(p[r][i]=='*') ans[r][i]=k;
                REP(j,0,G[r].size()) if(G[r][j]==i){
                    G[r].erase(G[r].begin()+j);
                    break;
                }
            }
        }

        printf("%d\n",maxn);
        REP(i,0,n) REP(j,0,n) printf("%d%c",ans[i][j],(j==n-1)?'\n':' ');
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/20143605--pcx/p/4948056.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值