【算法与数据结构】——图的着色算法(图论、着色问题、深度优先搜索) —— 酱懵静

图的着色问题

问题描述
存在一个无向图,要求给图中的点涂色,并且有线连接的点之间不能是同一种颜色

输入格式
第一行为两个正整数n,m( 0<n,m<100 ),分别表示录入的图的点数以及边数
第二行为一个正整数num,表示能用的颜色数(每种颜色用一个正整数来表示,从1开始逐渐增1的正整数)
之后为m行,每行两个数x,y,表示点x和y之间有一条边(点从1开始,为逐渐增1的正整数)

输出格式
按照点的顺序,输出所有点的着色方案,格式见样例输出(中间为’ \t’,空格+制表位)

样例输入1:
3 3
3
1 2
1 3
2 3

样例输出1:
point:1 color:1
point:2 color:2
point:3 color:3

point:1 color:1
point:2 color:3
point:3 color:2

point:1 color:2
point:2 color:1
point:3 color:3

point:1 color:2
point:2 color:3
point:3 color:1

point:1 color:3
point:2 color:1
point:3 color:2

point:1 color:3
point:2 color:2
point:3 color:1

样例输入2:
3 2
2
1 2
1 3

样例输出2:
point:1 color:1
point:2 color:2
point:3 color:2

point:1 color:2
point:2 color:1
point:3 color:1



---分割线---



对题目的简化解读:存在一个无向图,要求给图中的点涂色,并且有线连接的点之间不能是同一种颜色

分析:
深度优先搜索+回溯
着色问题,我们的解决思路应该从搜索出发。如果使用贪心,把互不连接的用同一颜色表示,是很难枚举完所有情况的的,并且难以保证每种情况间的唯一性。而使用搜索的思想,则可以避免这一问题。

我们从第一个点出发,不断地走进下一个点并且着色(需保证这种情况下着色的可行性),当走到最后一个点时(即当前点的序号大于了点的总数时)即是找到了一种着色方案。这时候,我们输出这个具体的着色方案,然后回溯。这里的回退是回退到当前涂某种颜色那个地方(即前一次调用dfs函数的那个循环那里)。于是在这不断地dfs下,其又将尝试对于当前点而言的其他着色方案并不断发散。
这样就保证了能把所有的着色方案都枚举到,并且彼此之间唯一。

本题实则是为蓝桥杯 历届试题 分考场这道题做预热~~~~~



---分割线---



下面给出本题完整代码:

#include<iostream>
using namespace std;

const int MAX=105;			//定义最大的顶点数
int n,m,num;				//分别代表点数、边数和可用颜色数
int map[MAX][MAX];			//对于小规模的数量可以直接使用邻接矩阵(也可以用向量,但没必要)
int color[MAX]; 			//color[i]=x表示第i个点涂上代号为x的颜色

bool judge(int pos,int col) //检测在当前pos位上涂上颜色代号为col的方案是否可行
{
	for(int i=1;i<=n;i++)
		if(map[pos][i] && color[i]==col) return false;
	return true; 
}
void dfs(int pos)
{
	if(pos>n)
	{
		for(int i=1;i<=n;i++)
			cout<<"point:"<<i<<" \tcolor:"<<color[i]<<endl;
		cout<<endl;
		return;
	}
	for(int i=1;i<=num;i++)
	{
		if(judge(pos,i))
		{
			color[pos]=i;
			dfs(pos+1);
			color[pos]=0;	//回退时必须把刚才点的着色去掉,否则会影响回退之后的dfs 
		}
	}
}
int main()
{
	int x,y; 
	cin>>n>>m>>num;
	for(int i=0;i<m;i++)
	{
		cin>>x>>y;
		map[x][y]=map[y][x]=1;
	}
	dfs(1); 
	return 0;
}

发布了30 篇原创文章 · 获赞 67 · 访问量 3037

猜你喜欢

转载自blog.csdn.net/the_ZED/article/details/101039652
今日推荐