第五章 图着色问题

来源:互联网 发布:淘宝自己组装iphone 编辑:程序博客网 时间:2024/06/15 05:03
图着色问题是最著名的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 wangchuanfreopen("C:\\in.txt","r",stdin);#endif // !wangchuanmemset(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 WANGCHUANfreopen("C:\\in.txt","r",stdin);#endif // !WANGCHUANfor(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];//检查是否有邻居标记过颜色kint 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着颜色1int 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 WANGCHUANfreopen("C:\\in.txt","r",stdin);#endif // !WANGCHUANmemset(color,0,sizeof(color));Greedy();for (int i=0; i<N; i++)cout<<"第"<<i<<"点标记颜色"<< color[i] <<endl;return 0;}

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



王川
2014/02/17
0 0
原创粉丝点击