1508: 地图的四着色
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 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);
}
}