UVA 10615 Rooks <二分图 + 正则二分图 + 完全匹配>

博客介绍了如何解决UVA在线判题系统的10615题"Rooks",即在一个棋盘上用最少的颜色涂车,确保车两两之间不冲突。问题转化为二分图匹配问题,通过构建正则二分图并寻找完备匹配来找到最少颜色数量,并给出了解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=11&page=show_problem&problem=1556

题意:一个NXN棋盘,车管理横纵两条线,在任何一个车管理的区域都不能放与自己相同的颜色车。求最少可以用几种颜色涂车,使车两两之间不发生冲突,输出填色一组情况即可。

分析:

二分图匹配,

S (0< S < 10)

N(0 ≤ N ≤ 100)

构建二分图

1)对于二分图染色,染色种数总是等于每一行或每一列的棋子数

2)建边,使其构造成k阶正则二分图,正则二分图必有完备匹配

3)对每一种颜色,匹配出可以涂相同颜色的,然后涂上颜色,并删除这个点(此点已经涂了颜色,匹配了)

#include<iostream>
#include<cstdio>
#include<ctime>
#include<string.h>
#include<cstring>
#include<vector>

using namespace std;
const int maxn = 110;
char s[maxn][maxn];
vector<int> g[maxn];
int  num[maxn][maxn],fg[maxn],link[maxn];
bool flag[maxn];
int n;
int rook;
void read()
{
    scanf("%d",&n);
    memset(s,0,sizeof(s));
    memset(num,0,sizeof(num));
    memset(fg,0,sizeof(fg));
    rook = 0;
    int ans ;
    for(int i = 0;i<n;i++)
    {
        scanf("%s",s[i]);
        g[i].clear();
        ans = 0;
        for(int j = 0;j<n;j++)
        {
            if(s[i][j] == '*')
            {
                 ans++;
                 fg[j]++;
                 g[i].push_back(j);
            }

        }
        rook = max(ans,rook);
    }
    for (int i = 0 ; i < n ; ++i)
    {
        ans = 0;
        for (int j = n-1 ; j >= 0 ; --j)
            if (s[j][i]=='*') ans++;
        rook = max(rook,ans);
    }
    for(int i=0;i<n;i++)
    {
        if(g[i].size()<rook)
        {
            for(int j=0;j<n&&g[i].size()<rook;j++)
               if(fg[j]<rook)
               while(fg[j]<rook&&g[i].size()<rook)
            {
                g[i].push_back(j);
                fg[j]++;
            }

        }
    }
}
bool dfs(int x)
{
    for(auto i=0;i<g[x].size();i++)
        if(!flag[g[x][i]])
    {
        int y = g[x][i];
        flag[y] = true;
        if(link[y] == -1 || dfs(link[y]))
        {
            link[y] = x;
            return true;
        }
    }
    return false;
}

void maxmatch()
{
    memset(link,-1,sizeof(link));
    for(int i=0;i<n;i++)
    {
        memset(flag,false,sizeof(flag));
        dfs(i);
    }
}
void solve()
{
    printf("%d\n",rook);
    int color = 0;
    int l,r;
    memset(num,0,sizeof(num));
   while(color < rook)
   {
       color++;
       maxmatch();
       for(int i=0;i<n;i++)
       {
           l= link[i];r=i;
           if(s[l][r] == '*') num[l][r] = color;
           for(auto j=0;j<g[l].size();j++) if(g[l][j] == r)
           {
               g[l].erase(g[l].begin()+j);
               break;
           }
       }

   }
}
void print()
{
    for(int i =0;i<n;i++)
    {
        printf("%d",num[i][0]);
        for(int j=1;j<n;j++)
            printf(" %d",num[i][j]);
        printf("\n");
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        read();
        solve();
        print();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值