CSU-1508 地图的四着色【Bfs+Dfs+思维剪枝】

224 篇文章 2 订阅

1508: 地图的四着色

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 164   Solved: 74
[ Submit][ Status]

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

Source


思路:


1、观察到最多的国家数只有30个,而且女朋友能够图的点的个数最多有5个,那么题目肯定是要往暴力Dfs染色方向去想的。

那么我们首先Bfs出所有点对应将其标号、

再接下来对于每个国家我们都建立图即可。


2、对于整个图,我们直接对于所有点都染色,其实跑的结果的速度就要看出题人的数据了。

直接染色暴力判断并且统计,是超时了的。

那么考虑思维优化。


我们不妨将表打出来看一下(这个是样例1的答案,对应1和2颜色是男的可以涂的颜色,3和4是女朋友可以涂的颜色):


我们发现,对于第一个国家,涂颜色1和涂颜色2对应Dfs出来的结果的数量是等同的,而且涂颜色3和涂颜色4对应Dfs出来的结果的数量也是等同的。

也就是说,对于第一次男孩来涂或者是第一次女孩来涂,涂哪种颜色的结果的数量都是等同的,那么沃我们可以进行优化。

如果第一次男孩来涂,我们让其只涂颜色1,不涂颜色2,那么ans==真正的ans/2.我按照这个优化交了一波,还是TLE了...(自己代码写的真的挫)

然后接下来还可以优化女孩,当第一次女孩来涂的时候,我们让其只涂颜色3,不涂颜色4,那么ans==真正的ans/4.

最终在结果*4输出即可。

此时提交Ac(17000+ms,真的好挫)

可能有更好的优化方案。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
struct node
{
    int x,y,num;
}now,nex;
vector<int >mp[300];
int contz,output;
int n,m;
int use[100];
int color[100];
int map[100][100];
int vis[100][100];
int num[100][100];
char a[100][100];
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
void Bfs_getnum(int x,int y)
{
    queue<node >s;
    vis[x][y]=1;
    now.x=x;
    now.y=y;
    s.push(now);
    while(!s.empty())
    {
        now=s.front();
        num[now.x][now.y]=contz;
        s.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&vis[nex.x][nex.y]==0)
            {
                if(a[nex.x][nex.y]==a[now.x][now.y])
                {
                    vis[nex.x][nex.y]=1;
                    s.push(nex);
                }
            }
        }
    }
    contz++;
}
void Getmap()
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            for(int k=0;k<4;k++)
            {
                int xx=i+fx[k];
                int yy=j+fy[k];
                if(xx>=0&&xx<n&&yy>=0&&yy<m)
                {
                    map[num[i][j]][num[xx][yy]]=1;
                    map[num[xx][yy]][num[i][j]]=1;
                }
            }
        }
    }
    for(int i=1;i<contz;i++)mp[i].clear();
    for(int i=1;i<contz;i++)
    {
        for(int j=1;j<contz;j++)
        {
            if(map[i][j]==1)mp[i].push_back(j);
        }
    }
}
int judge(int u,int col)
{
    int size=mp[u].size();
    for(int i=0;i<size;i++)
    {
        int v=mp[u][i];
        if(v==u)continue;
        if(color[v]==col)return 0;
    }
    return 1;
}
void Dfs(int u,int cont,int flag1,int flag2)
{
    if(u==contz)
    {
        int cnt=0;
        for(int i=1;i<=4;i++)
        {
            if(use[i]>0)cnt++;
        }
        if(cnt==4)
        {
            /*
            for(int i=1;i<contz;i++)
            {
                printf("%d ",color[i]);
            }
            printf("\n");*/
            output++;
        }
        return ;
    }
    for(int i=1;i<=4;i++)
    {
        color[u]=i;
        if(i==1||i==2)
        {
            if(flag1==0&&i==2)continue;
            if(judge(u,i)==1)
            {
                use[i]++;
                Dfs(u+1,cont,1,flag2);
                use[i]--;
            }
        }
        if(i==3||i==4)
        {
            if(flag2==0&&i==4)continue;
            if(cont>=1)
            if(judge(u,i)==1)
            {
                use[i]++;
                Dfs(u+1,cont-1,flag1,1);
                use[i]--;
            }
        }
        color[u]=0;
    }
}
int main()
{
    int kase=0;
    while(~scanf("%d%d",&n,&m))
    {
        output=0;
        contz=1;
        memset(vis,0,sizeof(vis));
        memset(map,0,sizeof(map));
        memset(num,0,sizeof(num));
        memset(use,0,sizeof(use));
        memset(color,0,sizeof(color));
        for(int i=0;i<n;i++)scanf("%s",a[i]);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(vis[i][j]==0)
                {
                    Bfs_getnum(i,j);
                }
            }
        }
        Getmap();
        Dfs(1,5,0,0);
        printf("Case %d: ",++kase);
        printf("%d\n",output*4);
    }
}







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值