深搜 图的M着色问题
吉林大学大二学生 东北师范大学附属中学OJ jinxi20111 2019.05.16
题目描述
给定无向连通图G和M种不同的颜色,用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G中每条边的2个顶点着不同的颜色,则称这个图是M可着色的。图的M着色问题是对于给定图G和M种颜色,找出所有不同的着色法。
对于给定的无向连通图G和M种不同的颜色,编程计算图的所有不同的着色法。
输入
第一行有3个正整数N,K和M,表示给定的图G有N个顶点和K条边,M种颜色。顶点编号为1,2……,N。接下来的K行中,每行有2个正整数U,V,表示图G的一条边(U,V)。
数据范围:1<N<=100 1<K<=2500 1<M<=6
输出
不同的着色方案数
样例输入
5 8 4
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
样例输出
48
分析过程
在东北师大附中的OJ上刚过的一道题
用将近一周烦恼,解决就用了15min
简述一下我 silly B 的烦恼过程
看到一道题,我习惯直奔数据范围
N为100,M为6 ,深搜量Nm最大为1W亿
OK,炸了
直接排除 直接打表和简单深搜
然后就是怀疑人生阶段(持续一周)
我在想出思路之前,基本上不会去查题解
于是我下意识去构建了图
图的存储方式,最基本的就是邻接矩阵和邻接表
在这道题中,显然很难取舍
那就分开考虑,首先先做邻接矩阵
一个100平方的矩阵显然不大。我就直接写了个二维数组。接下来的深搜过程可给老子烦坏了。
我的思路是,染好第一个色之后,给它相连的点一个无法染色的标识。
我可以说,当时我想的很美,因为这样做成功了的话,我的dfs里面就干干净净只有一个deep,并且代码量也会很小。
只能说,菜鸡你想的太美(律师函警告
因为染色过程中,势必会出现多个点连接一个点,这个时候,如何取消染色(回溯)成了一个难以解决的问题。
谁做谁知道。至少当时我没做出来。
然后我就去做了个邻接表,打算用宽搜BFS去做。
然而,找前置点成了问题,即你根本不知道你为什么不能染某个色。
代码不粘了,太二了,又臭又长又超时。
两个都解不了。
懵了。
于是我去北苑一公寓三楼西北角的洗手间的第三个坑蹲了一会
有点便秘,没蹲出来(双关?)
没办法,暂时放弃。
在将近一周之中,我想了很多办法。比如,将边进行排序,用来节省生成邻接表的时间。(后来发现这很智障
又比如,生成树,然后逐层染色。结果仔细读读题,根本没说没有回路,,也就说有可能改不成树。
今天实验课,我闲得没事,在北苑一公寓三楼西北角的洗手间的第三个坑蹲坑的时候,把题拿了出来。
艹,这题跟怎么存图没啥关系,,
其实这道题的优化是有一些的。但是思路对了,应该是用不上优化的。
我们需要做的是,把图存到初始化为False的邻接矩阵中,然后用回溯法去遍历Color
回溯遍历?
如下:
代码一,条件分别代表 相连 同色 已染色
//回溯条件 相连 同色 已染色
if ((g[deep][j])&&(c[deep]==c[j])&&(c[deep]!=0))
{
flag=false;
}
代码二,回溯行为,取消染色
if (flag)
{
dfs(deep+1);
}
c[deep]=0;
这样做,其实纯粹是灵光乍现。因为我一直觉得这样做既浪费时间,也浪费空间。但在这道题里,很巧妙的在空间和时间中找到了一个平衡点。深搜100个点,找点的过程是6*1002 ,不大,存边的矩阵是1002 ,也不大。可以说是非常完美(牛气叉腰!)
下面是AC代码展示
//吉林大学大二学生 东北师范大学附属中学OJ jinxi20111 2019.05.07
//MythCoffee 图的M着色问题
#include<iostream>
using namespace std;
int n,k,m,ans;
int g[101][101],c[101];
void dfs(int deep)
{
if (deep>n)
{
ans++;
}
else
{
int i,j;
bool flag;
for(i=1;i<=m;i++)
{
c[deep]=i;
flag=true;
j=1;
while ((j<=n)&&(flag))
{
if ((g[deep][j])&&(c[deep]==c[j])&&(c[deep]!=0))
{
flag=false;
}
j++;
}
if (flag)
{
dfs(deep+1);
}
c[deep]=0;
}
}
}
int main()
{
int s,j,t1,t2;
cin>>n>>k>>m;
for(s=1;s<=n;s++)
{
for(j=1;j<=n;j++)
{
g[s][j]=false;
}
}
for(s=1;s<=k;s++)
{
cin>>t1>>t2;
g[t1][t2]=true;
g[t2][t1]=true;
}
dfs(1);
cout<<ans;
return 0;
}
上一篇: Python基础入门教程(基于Python3.8)
下一篇: vue的作用域插槽是啥?