寒假Day31:CSU1508-地图的四着色-bfs+dfs
题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1508
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、
先用bfs1给每一点进行标号,用第一组样例来说
AABB
BBAA,
标完号之后就变成了
1122
3344
2、
用bfs2把相邻的国家连接起来,用邻接表存储,vector可以勉强水过
用上面那组例子,连接好之后就变成
1-2-3
2-1-4
3-1-4
3、
每一种可行情况ans++,最后的结果*4不会超时,因为有四种可能,AC、AD、BC、BD,男生先染、女生后染。
邻接表过的,很多处理细节需要注意,还得一遍遍尝试。
AC代码:
#include<stdio.h> #include<iostream> #include<string.h> #include<queue> using namespace std; typedef long long ll; char a[25][25]; int n,m,num,tot,ans; bool book1[35][35],book2[35][35]; int id[25][25],head[35],color[35]; int to[4][2]= {{0,1},{0,-1},{1,0},{-1,0}}; struct node { int x,y; } p,q; struct E { int v,nextt; } e[1005]; void add(int u,int v) { e[tot].v=v; e[tot].nextt=head[u]; head[u]=tot++; } void bfs1(int x,int y) { id[x][y]=num;//横纵坐标 p.x=x; p.y=y; queue<node>Q; Q.push(p); while(!Q.empty()) { q=Q.front(); Q.pop(); for(int i=0; i<4; i++) { p=q; p.x+=to[i][0]; p.y+=to[i][1]; if(p.x>=0&&p.x<n&&p.y>=0&&p.y<m&&a[p.x][p.y]==a[q.x][q.y]&&id[p.x][p.y]==0) { id[p.x][p.y]=num; Q.push(p); } } } } void bfs2(int x,int y) { queue<node>Q; p.x=x; p.y=y; Q.push(p); while(!Q.empty()) { q=Q.front(); Q.pop(); book1[q.x][q.y]=1; for(int i=0; i<4; i++) { p=q; p.x+=to[i][0]; p.y+=to[i][1]; //if(p.x>=0&&p.x<n&&p.y>=0&&p.y<m&&book1[p.x][p.y]==0) if(p.x>=0&&p.x<n&&p.y>=0&&p.y<m) { if(id[p.x][p.y]!=id[q.x][q.y]) { //add(id[p.x][p.y],id[q.x][q.y]); //add(id[q.x][q.y],id[p.x][p.y]); book2[id[p.x][p.y]][id[q.x][q.y]]=1; book2[id[q.x][q.y]][id[p.x][p.y]]=1; continue; // Q.push(p); } if(book1[p.x][p.y]==0) Q.push(p);//MLE } // if(book1[p.x][p.y]==0) // Q.push(p);//MLE } } } int check(int s,int k) { //不能传入i、k for(int i=head[s]; i!=-1; i=e[i].nextt) { if(color[e[i].v]==k) return 0; } return 1; } void dfs(int i,int a1,int a2,int a3,int a4)//涂到第几个城市,四种颜色分别涂了几个 { if(num+1==i) { if(a1&&a2&&a3&&a4) ans++; return ; }//只能写成这样,改了一下要么RT要么WA color[i]=0; if(check(i,0)) dfs(i+1,a1+1,a2,a3,a4);//第一种颜色 color[i]=1; if(a1&&check(i,1)) dfs(i+1,a1,a2+1,a3,a4);//二 color[i]=2; if(a3+a4<5&&check(i,2)) dfs(i+1,a1,a2,a3+1,a4);//三 color[i]=3; if(a3&&a3+a4<5&&check(i,3)) dfs(i+1,a1,a2,a3,a4+1);//四 } int main() { int t=1; while(~scanf("%d %d",&n,&m)) { memset(id,0,sizeof(id)); memset(book1,0,sizeof(book1)); memset(book2,0,sizeof(book2)); memset(head,-1,sizeof(head)); for(int i=0; i<n; i++) scanf("%s",a[i]);//注意一下 num=0; for(int i=0; i<n; i++) { for(int j=0; j<m; j++) { if(id[i][j]==0) { num++; bfs1(i,j); } } }//vs bfs1(0,0) tot=0; for(int i=0; i<n; i++) { for(int j=0; j<m; j++) { if(book1[i][j]==0) bfs2(i,j); } } // for(int i=0; i<n; i++) // { // for(int j=0; j<m; j++) // { // if(book[i][j]==0) // bfs2(i,j); // } // } for(int i=1; i<=num; i++) { for(int j=1; j<i; j++)//到n也WA { if(book2[i][j]==1) add(i,j); } } ans=0; dfs(1,0,0,0,0); printf("Case %d: %d\n",t++,ans*4); } return 0; }
Thinking
反正这题一点也不好写,稍微改改就要错,提交了二十几,写完我就看英语去~~~
我觉得难的题我过了也没啥用,
最近天天凌晨睡觉,一个代码扣几个小时,即使再写也不一定能过,
感觉还是只能做简单题,
我还是去刷cf的简单题叭~~~
再这样下去,一事无成,时间也耗在着,几个小时做一道题,好几天都这样,又和以前一样了~
还是要加油鸭