【题目描述】四色地图(map.cpp/c/pas)
地图四色定理(Four color theorem)最先是由一位叫古德里(Francis Guthrie)的英国大学生提出来的。其内容是:“任何一张地图只用四种颜色就能使具有共同边界的国家着上不同的颜色。”用数学语言表示,即“将平面任意地细分为不相重叠的区域,每一个区域总可以用1,2,3,4这四个数字之一来标记,而不会使相邻的两个区域得到相同的数字。”这里所指的相邻区域,是指有一整段边界是公共的。如果两个区域只相遇于一点或有限多点,就不叫相邻的。因为用相同的颜色给它们着色不会引起混淆。
如图所示,给出一任意地图,溃败的黑暗军团就散布在该地图的各个区域,墨老师一行四人需要带队搜索各区域,为了防止混乱,规定彼此搜索的区域互不相邻,请尝试如何分配。
【输入格式】
第一行为N(1<N≤26),表示区域数。随后N行描述各区域之间是否相邻。
【输出格式】
以1,2,3,4分别代表四人的编号(颜色),输出各区域的编号。
【输入样例】
4
1 2 3 (表示区域1与区域2,3相邻,以下3行同理)
2 1 4
3 1 4
4 3 2
【输出样例】
1 2 2 1(表示分别编号即颜色为1,2,2,1)
这他妈是他妈的T1?
这是尼玛人做的题?
不吐槽了我们先来看一下这题咋做咋分析
cout<<"-1";显然是正解(输出-1不换行还不给分我真吐了)
认真分析开始
现在看下输入时给的条件
会给你区块的数量and区块之间的关系
这货输入要是个确定的
那肯定就是个小学奥数题了(大雾
小学生都知道先画图我他妈怎么就不会呢
嗯应该先建图
看这个数据量(n<=26)
建一个30个点的图(边和颜色)
1 int n,a[30][30],cl[30]={0};//定义顶点和连接两个顶点之间边以及每个点的颜色(颜色都是0,表示未被涂色) 2 bool vsd[30];//每个点区域是否被标过色
其实这货是邻接矩阵。。。
1 //邻接矩阵 2 int i,j,k,w; 3 scanf("%d%d",&G->n,&G->e); //输入顶点数和边数 4 for(i = 0;i < G->n;i++) //读入顶点信息,建立顶点表 5 { 6 G->vexs[i]=getchar(); 7 } 8 for(i = 0;i < G->n;i++) 9 { 10 for(j = 0;j < G->n;j++) 11 { 12 G->edges[i][j] = 0; //邻接矩阵初始化 13 } 14 } 15 for(k = 0;k < G->e;k++) 16 { 17 //读入e条边,建立邻接矩阵 18 scanf("%d%d%d",&i,&j,&w); //输入边(v i ,v j )上的权w 19 G->edges[i][j]=w; 20 } 21 }//CreateMGraph
我太蒻了%%%%%%%%
然后写个快读函数(输入)
int kd(int &x) { if(s[x]==' ') //到时候整行连着空格输入,所以要先判断空格 { x++; //可爱的空格计数器 } int kd=0; while((s[x]<='9')&&(s[x]>='0'))//区域编号也可能是两位数,这时候显然不可能直接把这个数输入进来,就需要分别输入每一位,然后再合起来
{ kd*=10; kd+=s[x++]-'0'; } return kd; }
先不管DFS内部分,先处理一下输入的问题
cin>>n;//输入区域数量 for(int i=1; i<=n; i++) { for(int j=1;j<=n;j++) { a[i][j]=-1;//定义为负一,表示没有连起来;也就是初始化图中的边 } } getline(cin,s);//输入一行字符 for(int i=1; i<=n; i++)//把每一行都用这样的方法输入 { getline(cin,s); int j=0; kd(j); while(j<s.length()) { int q=kd(j); a[i][q]=1; a[q][i]=1; j++; } }
for(int i=1; i<=n; i++)
{
DFS(i);
}
cout<<endl;
return 0;
}
目前总算是完成了输入的问题
下面看看核心代码DFS(这题核心代码明明是输入好吧...
void DFS(int x) { vsd[x]=1; bool tp[5]= {0}; for(int i=1; i<=n; i++) { if((vsd[i])&&(a[x][i]==1)) { tp[cl[i]]=1; } } for(int i=1; i<=4; i++) { if(!tp[i]) { cl[x]=i; cout<<cl[x]<<" "; return; } } return; }
各位巨佬显然看出来这好像跟正常的DFS没啥区别对吧
就是没啥区别
其实思路也很简单
从区域1开始标色,首先把它先标记为1
然后根据上面输入进来的关系,看看与它相连的其他点是什么颜色
如果其他点已经被标过色了
那么标其他点所用的颜色这时候就不能用来标现在的点
而且我们把优先级设置成从1到4
也就是所谓的所有能标的颜色中选择序号最小的那一种
输入数据保证有解,而且这个定理已经被证明过了
那么最后顺序输出结果就行了
附上完整AC代码
#include<iostream> #include<cstring> #include<string> #include<cstdio> using namespace std; int n,a[30][30],cl[30]= {0}; bool vsd[30]; string s; int kd(int &x) { if(s[x]==' ') { x++; } int ru=0; while((s[x]<='9')&&(s[x]>='0')) { ru*=10; ru+=s[x++]-'0'; } return ru; } void DFS(int x) { vsd[x]=1; bool tp[5]={0}; for(int i=1; i<=n; i++) { if((vsd[i])&&(a[x][i]==1)) { tp[cl[i]]=1; } } for(int i=1; i<=4; i++) { if(!tp[i]) { cl[x]=i; cout<<cl[x]<<" "; return; } } return; } int main() { //freopen("map.in","r",stdin); //freopen("map.out","w",stdout); cin>>n; for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { a[i][j]=-1; } } getline(cin,s); for(int i=1; i<=n; i++) { getline(cin,s); int j=0; kd(j); while(j<s.length()) { int q=kd(j); a[i][q]=1; a[q][i]=1; j++; } } for(int i=1; i<=n; i++) { DFS(i); } cout<<endl; return 0; }