CSU 1508 地图的四着色

1508: 地图的四着色

Time Limit: 20 Sec       Memory Limit: 128 Mb       Submitted: 230       Solved: 105    

Description

有一个R行C列的网格地图,每个国家是一个四连通区域。你的任务是用红,绿,蓝,黄四种颜色给地图着色,使得相邻国家的颜色不同。
一个人着色比较无趣,所以你想请女朋友陪你一起涂——你涂红绿,她涂蓝黄。当然,绅士是不会让让女朋友受累的,所以她最多只需涂5个国家(恰好5个也行)。
你的任务是统计有多少种着色的方法。注意,每个颜色都至少要用一次。

Input

输入包含不超过100组数据。每组数据第一行为两个整数R和C (1<=R,C<=20),即网格的行数和列数。以下R行每行C个大写字母。相同字母所组成的四连通区域代表一个国家。输入保证国家数目不超过30,并且大多数测试点的国家数都比较小。

Output

对于每组数据,输出测试点编号和着色方案数。

Sample Input

2 4
AABB
BBAA
1 5
ABABA
4 7
AABAABB
ABBCCCB
BBAACBB
CCABBAC

Sample Output

Case 1: 24
Case 2: 144
Case 3: 3776

Hint

思路:先对图中进行bfs为每个国家编号,暴力去找出每个国家都与哪些国家相邻并建边,之后就产生了一个新图,就把问题转化为有多少种染色方案能使得相连的点的颜色两两互不相同。正解应该是二分图染色,不过用点组合数学加上dfs也是能比较快的跑出来。
组合思想:我们可以强行让男的第一次先涂第一种颜色,女的第一次先涂第三种颜色。(对于此题,先涂哪一个颜色都是等价的,所以结果是2*2倍)(来源于: http://blog.csdn.net/acm_cxq/article/details/52224876
要注意的是答案会爆int

Source

湖南省第十届大学生计算机程序设计竞赛

示例程序:
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
struct jj
{
    int x,y;
};
struct kk
{
    int v,next;
}w[900];			//新图
int h[30],numw,mpid[20][20],n,m,num,v[30],walk[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
long long sum;
char mp[20][21];
void insert(int u,int v)
{
    w[numw].v=v;
    w[numw].next=h[u];
    h[u]=numw++;
}
void bfs(int x,int y)
{
    int i;
    struct jj s,pos;
    queue<struct jj>q;
    mpid[x][y]=num;
    s.x=x;
    s.y=y;
    q.push(s);
    while(q.empty()==0)
    {
        s=q.front();
        q.pop();
        for(i=0;4>i;i++)
        {
            pos.x=s.x+walk[i][0];
            pos.y=s.y+walk[i][1];
            if(pos.x>=0&&pos.x<n&&pos.y>=0&&pos.y<m&&mpid[pos.x][pos.y]==-1&&mp[x][y]==mp[pos.x][pos.y])
            {
                mpid[pos.x][pos.y]=num;
                q.push(pos);
            }
        }
    }
}
int judge(int deep,int kind)
{
    int i;
    for(i=h[deep];i!=-1;i=w[i].next)
    {
       if(v[w[i].v]==kind)				//使用的颜色不符合条件
       {
           return 0;
       }
    }
    return 1;
}
void dfs(int deep,int buff,int status)
{
    int i;
    if(deep==num)
    {
        if(status==15)				//当状态为15的时候说明每一种颜色都用上了
        {
            sum++;
        }
        return;
    }
    if(judge(deep,1)==1)
    {
        v[deep]=1;
        dfs(deep+1,buff,status|1);
        v[deep]=0;
    }
    if(judge(deep,2)==1&&(status&1)!=0)
    {
        v[deep]=2;
        dfs(deep+1,buff,status|2);
        v[deep]=0;
    }
    if(buff==0)
    {
        return;
    }
    if(judge(deep,3)==1)
    {
        v[deep]=3;
        dfs(deep+1,buff-1,status|4);
        v[deep]=0;
    }
    if(judge(deep,4)==1&&(status&4)!=0)
    {
        v[deep]=4;
        dfs(deep+1,buff-1,status|8);
        v[deep]=0;
    }
}
int main()
{
    int i,i1,i2,i3,x,y;
    for(i=1;scanf("%d %d",&n,&m)!=EOF;i++)
    {
        for(i1=0;n>i1;i1++)
        {
            scanf("%s",mp[i1]);
        }
        memset(mpid,-1,sizeof(mpid));				//每个点所属的国家编号
        memset(h,-1,sizeof(h));
        num=0;
        sum=0;
        numw=0;
        for(i1=0;n>i1;i1++)
        {
            for(i2=0;m>i2;i2++)
            {
                if(mpid[i1][i2]==-1)
                {
                    bfs(i1,i2);				//bfs为国家编号
                    num++;
                }
            }
        }
        for(i1=0;n>i1;i1++)
        {
            for(i2=0;m>i2;i2++)
            {
                for(i3=0;4>i3;i3++)				//暴力找相邻国家
                {
                    x=i1+walk[i3][0];
                    y=i2+walk[i3][1];
                    if(x>=0&&x<n&&y>=0&&y<m&&mpid[i1][i2]!=mpid[x][y])
                    {
                        insert(mpid[i1][i2],mpid[x][y]);
                    }
                }
            }
        }
        memset(v,0,sizeof(v));				//初始化所有点都未上色
        dfs(0,5,0);
        printf("Case %d: %lld\n",i,sum*4);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值