第五章 图着色问题

图着色问题是最著名的NP-完全问题,由此还引出了著名的四色定理,四色猜想还曾是一百年来历史上最难的数学难题之一,当然,我不是学数学的,对这些猜想证明一窍不通,也不感冒,但是,图着色问题作为一道算法题目确是很值得研究的,所以作为一名的大学生程序员的我,把它另作一章是无可厚非的
问题描述自不必多说,对于这个问题,我首先想到的就是用搜索+回溯的思想,一个一个的去试,先拿1种颜色图,不行再加一种,等等,代码先贴上
#include <iostream>
#include <cstring>
using namespace std;

#define N 8

//表示一张图
int g[][N]={
	{0,1,1,1,0,0,1,0},
	{1,0,1,1,1,0,0,0},
	{1,1,0,0,1,1,0,0},
	{1,1,0,0,1,0,1,0},
	{0,1,1,1,0,1,1,1},
	{0,0,1,0,1,0,0,1},
	{1,0,1,1,1,0,0,1},
	{0,0,0,0,1,1,1,0}
};
//标记的颜色
int color[N];

//检查是否有邻居标记过同一种颜色
int ok(int t){
	for(int i=0;i<N;i++)
		if(i!=t&&g[t][i]&&color[t]==color[i])
			return 0;
	return 1;
}
//试着用m种颜色进行标记
bool traceback(int t,int m){
	if(t>=N)return true;

	for(int i=1;i<=m;i++){
		color[t]=i;
		if(ok(t)&&traceback(t+1,m))return true;
		color[t]=0;
	}
	return false;
}
int main()
{
#ifndef wangchuan
	freopen("C:\\in.txt","r",stdin);
#endif // !wangchuan
	
	memset(color,0,sizeof(color));
		
	for(int j=1;j<=4;j++){
		if(traceback(0,j)){
			for(int i=0;i<N;i++){
				cout<<"第"<<i<<"点标记颜色"<<color[i]<<endl;
			}
			break;
		}
	}
	return 0;
}

还有一种Welch Powell法,实质上是一种贪心策略

a).将G的结点按照度数递减的次序排列.

b).用第一种颜色对第一个结点着色,并按照结点排列的次序 

   对与前面着色点不邻接的每一点着以相同颜色.

c).用第二种颜色对尚未着色的点重复步骤b).用第三种颜色

   继续这种作法, 直到所有点着色完为止.

//图着色问题
//WelchPowell法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define N 8

//表示一张图
int g[][N]={
	{0,1,1,1,0,0,1,0},
	{1,0,1,1,1,0,0,0},
	{1,1,0,0,1,1,0,0},
	{1,1,0,0,1,0,1,0},
	{0,1,1,1,0,1,1,1},
	{0,0,1,0,1,0,0,1},
	{1,0,1,1,1,0,0,1},
	{0,0,0,0,1,1,1,0}
};

struct node{
	int color;//标记的颜色
	int degree;//节点的度数(出度或入度)
	int index;//因为要排序,所以先要记录节点所在位置

	bool operator<(node &t){
		return degree>t.degree;
	}
}Node[N];


void WelchPowell(){
    sort(Node,Node+N);
	int k = 0;//K 代表第几种颜色
	while (true) {
		k++;
		int i;
		for (i = 0; i < N; i++){//先找到第一个未着色的节点
			if (Node[i].color == 0) {
				Node[i].color = k;
				break;
			}
		}
		if (i == N)//循环退出的条件,所有节点都已着色
			break;
		//再把所有不和该节点相邻的节点着相同的颜色
		for(int j=0; j<N; j++){
			if(Node[j].color ==0 &&g[Node[i].index][Node[j].index] == 0&&i!=j)
				Node[j].color = k;
		}
	}
}
int main()
{
#ifndef WANGCHUAN
	freopen("C:\\in.txt","r",stdin);
#endif // !WANGCHUAN
	for(int i=0;i<N;i++){
		Node[i].index=i;
		Node[i].color=0;
		Node[i].degree=0;
		for(int j=0;j<N;j++){
			if(g[i][j])Node[i].degree++;
		}
	}
	WelchPowell();

	for (int i=0; i<N; i++)
		cout<<"第"<<Node[i].index<<"点标记颜色"<< Node[i].color <<endl;
	return 0;
}

还有一种简单的贪心算法,先拿一种颜色标记尽量多的点,如果还有点没标,再拿另一种颜色标记,如此反复
//图着色问题
//贪心法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define N 8

//表示一张图
int g[][N]={
	{0,1,1,1,0,0,1,0},
	{1,0,1,1,1,0,0,0},
	{1,1,0,0,1,1,0,0},
	{1,1,0,0,1,0,1,0},
	{0,1,1,1,0,1,1,1},
	{0,0,1,0,1,0,0,1},
	{1,0,1,1,1,0,0,1},
	{0,0,0,0,1,1,1,0}
};

int color[N];

//检查是否有邻居标记过颜色k
int ok(int t,int k){
	for(int i=0;i<N;i++)
		if(i!=t&&g[t][i]&&k==color[i])
			return 0;
	return 1;
}

void Greedy(){
	color[0]=1;//先给节点0着颜色1

	int k = 0;//K 代表第几种颜色
	while (true) {
		k++;
		//如果所有顶点均着色,退出循环
		int i;
		for(i=1;i<N;i++)if(!color[i])break;
		if(i==N)break;
		//

		for(int i=1;i<N;i++){
			if(color[i])continue;
			//判断i点能否着颜色k,即i的邻居节点没有着颜色k的
			if(ok(i,k))color[i]=k;
		}
	}
}
int main()
{
#ifndef WANGCHUAN
	freopen("C:\\in.txt","r",stdin);
#endif // !WANGCHUAN
	memset(color,0,sizeof(color));
	Greedy();

	for (int i=0; i<N; i++)
		cout<<"第"<<i<<"点标记颜色"<< color[i] <<endl;
	return 0;
}

当然还有更加高级的蚁群算法,但是不会写实现代码,等会写的时候再贴上吧



王川
2014/02/17
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值