C语言验证四色定理并输出所有染色方案

题目

在这里插入图片描述

思路
  1. 首先对一个多边形进行着色,着色后判断是否满足要求,如果满足要求则继续对其他多边形进行着色
  2. 如果不满足要求则撤销当前着色并回溯,采用其他着色方案
  3. 递归如此,直到地图全部着色完成
验证四色定理
	/*
	文件组织方式
	5 8      //5个顶点,8条无向边
	ABCDE    //顶点
	AB       //边
	AC    
	AD
	CD
	CE
	CB
	DE
	BE
	*/
	#include<stdio.h>
	#include<stdlib.h>
	
	/* 宏定义 */
	#define MAX_VERTEX_NUM 20	  //最大顶点个数 
	
	/*定义地图可染的颜色*/
	typedef enum{ None, Red, Green, Blue, Yellow }GraphColor;	//无-0,红-1、绿-2、蓝-3、黄-4
		
	/*表结点*/
	typedef struct ArcNode{
		int adjvex;				  //顶点序号 
		struct ArcNode *nextarc;  //指向下一条弧的指针 
	}ArcNode;
	
	/*头结点*/
	typedef char VertexType;  //图顶点类型 
	typedef struct VNode{
		VertexType data;	  //顶点信息
		ArcNode *firstarc;
		int color;            //该顶点的颜色
	}VNode, AdjList[MAX_VERTEX_NUM+1];
	
	/*图(邻接表)的存储表示*/
	typedef struct{
		AdjList vertices;	 //邻接表
		int vexnum,	arcnum;	 //图的当前顶点数和弧数
	}ALGraph;
	
	/*寻找顶点u在vertices中对应的位置*/
	int LocateVex_AL(ALGraph G, VertexType u){
		int i;
		for(i=1; i<=G.vexnum; i++){
			if(G.vertices[i].data==u)
				return i;
		}
		return 0;
	}
	
	/*创建无向图*/
	int CreateUDG(FILE *fp, ALGraph *G){
		int i, j, k;
		VertexType v1, v2;
		char tmp;
		ArcNode *p, *q;
		ArcNode *r[MAX_VERTEX_NUM+1];	//作为访问标记 
		
		fscanf(fp, "%d%d", &((*G).vexnum), &((*G).arcnum));
		
		/*
		对于fscanf,其实是存在陷阱的。
		回车键或空格键、制表键本身也都算是一个字符。 
		当输入的变量的格式是char字符格式时,&c就会自动接收空格键
		*/ 
		fscanf(fp, "%c", &tmp);	 //跳过int和char间的换行符【int和char之间不知道为什么存在一个换行符】
		fscanf(fp, "%c", &tmp);	 //跳过换行符 
		for(i=1; i<=(*G).vexnum; i++){
			fscanf(fp, "%c", &((*G).vertices[i].data)); //vertices[0]不存储
			(*G).vertices[i].firstarc = NULL;
			(*G).vertices[i].color = None; //先将该顶点的颜色初始化为无色(0)
			r[i] = NULL;  //将访问标记 置为空
		}
		
		for(k=1; k<=(*G).arcnum; k++){
	
			fscanf(fp, "%c", &tmp);	  //跳过换行符 
			fscanf(fp, "%c%c", &v1, &v2);
			
			i = LocateVex_AL(*G, v1); //寻找顶点u在vertices中对应的位置
			j = LocateVex_AL(*G, v2);
			
			if(!i || !j)			 //保证获取的顶点存在
				return 0;
			
			/*v1->v2*/
			p = (ArcNode *)malloc(sizeof(ArcNode));
			if(!p)
				exit(0);
			p->adjvex = j;      //顶点v2的序号为j 
			p->nextarc = NULL;
			
			if(r[i]==NULL)	 //说明还没有边与顶点v1相连
				(*G).vertices[i].firstarc = p;	//加入到邻接表 
			else
				r[i]->nextarc = p;	//令p连接到当前顶点边链表最后一个结点后面
			r[i] = p; //r[i]指向当前顶点边链表最后一个结点的位置
	
			/*v2->v1*/
			q = (ArcNode *)malloc(sizeof(ArcNode));
			if(!q)
				exit(0);
			q->adjvex = i;   //顶点v1的序号为i
			q->nextarc = NULL;
			
			if(r[j]==NULL)		//说明还没有边与顶点v2相连 
				(*G).vertices[j].firstarc = q;		//加入到邻接表 
			else
				r[j]->nextarc = q;			
			r[j] = q;
		}
		
		return 1;
	}
	
	/*判断与序号为nodeOrder的顶点直接相邻的边是否有相同的颜色,若有,说明此方案不行*/
	int isColorOK(ALGraph G, int nodeOrder) { 
		ArcNode *p =G.vertices[nodeOrder].firstarc;
		while(p){
			if(G.vertices[nodeOrder].color == G.vertices[p->adjvex].color)
				return 0;
			p = p->nextarc;
		}
		return 1;
	}
	
	/*回溯法对图着色【此题与八皇后问题神似】*/
	/*只要有一个符合条件的解,就返回*/
	int getColorPowset(ALGraph *G, int colorNum, int step, VertexType vex, int tarColor) {  
		int i,pos;
		pos = LocateVex_AL(*G, vex); //寻找顶点vex在vertices中对应的位置
		if(step > (*G).vexnum){ //如果step>(*G).vexnum,说明所有顶点的染色都符合条件,它们都已被染色【递归结束的标志】
			if((*G).vertices[pos].color == tarColor){  //在vex所在区域图上了tarColor颜色
				return 1; //当这一层通过时,将会层层返回1,这个染色结果就是符合条件的解
			}
		} 
		else{
			for(i = 1; i<=colorNum; i++){
				(*G).vertices[step].color = i; //先在vertices[step]处染上颜色i
				/*判断能否在vertices[step]处染色【即判断该顶点四周有没有相同的颜色】*/
				if(isColorOK(*G, step)){ //若可以
					if(getColorPowset(G, colorNum, step+1, vex, tarColor))  //到下一个顶点进行递归
						return 1; //当上一个条件通过时【递归返回的是1,说明所有顶点都已染上符合条件的颜色了】,将会层层返回1
				}
				/*
				两种情况:
				1、vertices[step]处不能染成i颜色【不符合染色条件】
				2、vertices[step]处可以染成i颜色,但由于vertices[step+1]处无法放置符合条件的颜色,退回到这里,因此vertices[step]处放i颜色不合适,它不能放这里,否则vertices[step+1]处无法合理染色
				总之:要将vertices[step]处染的颜色i去掉【回朔】,然后再次进入for循环,换其它颜色染vertices[step]
				*/
				(*G).vertices[step].color = None; //回朔
			}
		}
		return 0;
	}
	
	/*输出图*/
	void OutputALGraph(ALGraph G){
		int i, j;
		ArcNode *p;
		
		if(!G.vexnum && !G.arcnum)
			printf("空图(表)!\n");
		else{
			for(i=1; i<=G.vexnum; i++){
				printf("%c→", G.vertices[i].data);
				p = G.vertices[i].firstarc;
				while(p){
					printf(" %c", G.vertices[p->adjvex].data);
					p = p->nextarc;
				}
				printf("\n");	
			}
		}
	}
	
	/*展示染色结果*/
	void showResult(ALGraph G){
		int i, j;
		ArcNode *p;
		
		if(!G.vexnum && !G.arcnum)
			printf("空图(表)!\n");
		else{
			for(i=1; i<=G.vexnum; i++){
				printf("区域%c→→颜色%d\n", G.vertices[i].data, G.vertices[i].color);	
			}
		}
	}
	
	int main(){
		ALGraph G;
		FILE *fp;
		int vex, tarColor;
		printf("创建无向图...\n");
		fp = fopen("2015-08_UDG_AL.txt", "r");
		CreateUDG(fp, &G); 
		fclose(fp);
		printf("\n");
		printf("输出图的邻接表 G = \n");		
		OutputALGraph(G);
		printf("可选区域:A,B,C,D,E\n");
		printf("可选颜色:1【红】,2【绿】,3【蓝】,4【黄】\n");
		printf("请输入一种着色方案【例如:A 1】:");
		scanf("%c%d", &vex, &tarColor);//在顶点vex所在区域染上tarColor颜色
		/*颜色的种类是4,刚开始从vertices[1]开始试探*/
		if(getColorPowset(&G, 4, 1, vex, tarColor)) { //如果最后染色成功
			printf("染色成功,其中一种方案如下:\n");
			showResult(G);
		}
		else 
			printf("染色失败,方案不正确\n"); //染色失败
	
		return 1;
	}
输出所有染色方案
	/*
	文件组织方式
	5 8         //5个顶点,8条无向边
	1 2 3 4 5   //顶点
	1 2         //边
	1 3
	1 4
	3 4
	3 5
	3 2
	4 5
	2 5
	*/
	#include<stdio.h>
	#include<stdlib.h>
	
	/*宏定义*/
	#define MAX_VERTEX_NUM 20	//最大顶点个数 
	
	/*全局变量*/
	int order;		//跟踪每一种解法 
	
	/*定义地图可染的颜色*/
	typedef enum{ None, Red, Green, Blue, Yellow }GraphColor;	//无-0,红-1、绿-2、蓝-3、黄-4
		
	/*表结点*/
	typedef struct ArcNode{
		int adjvex;				  //顶点序号 
		struct ArcNode *nextarc;  //指向下一条弧的指针 
	}ArcNode;
	
	/*头结点*/
	typedef int VertexType;   //图顶点类型 
	typedef struct VNode{
		VertexType data;	  //顶点信息
		ArcNode *firstarc;
		int color;            //该顶点的颜色
	}VNode, AdjList[MAX_VERTEX_NUM+1];
	
	/*图(邻接表)的存储表示*/
	typedef struct{
		AdjList vertices;	 //邻接表
		int vexnum,	arcnum;	 //图的当前顶点数和弧数
	}ALGraph;
	
	/*寻找顶点u在vertices中对应的位置*/
	int LocateVex_AL(ALGraph G, VertexType u){
		int i;
		for(i=1; i<=G.vexnum; i++){
			if(G.vertices[i].data==u)
				return i;
		}
		return 0;
	}
	
	/*创建无向图*/
	int CreateUDG(FILE *fp, ALGraph *G){
		int i, j, k;
		VertexType v1, v2;
		char tmp;
		ArcNode *p, *q;
		ArcNode *r[MAX_VERTEX_NUM+1];	//作为访问标记 
		
		fscanf(fp, "%d%d", &((*G).vexnum), &((*G).arcnum));
	
		for(i=1; i<=(*G).vexnum; i++){
			fscanf(fp, "%d", &((*G).vertices[i].data)); //vertices[0]不存储
			(*G).vertices[i].firstarc = NULL;
			(*G).vertices[i].color = None; //先将该顶点的颜色初始化为无色(0)
			r[i] = NULL;  //将访问标记 置为空
		}
		
		for(k=1; k<=(*G).arcnum; k++){
	
			fscanf(fp, "%d%d", &v1, &v2);
			
			i = LocateVex_AL(*G, v1); //寻找顶点u在vertices中对应的位置
			j = LocateVex_AL(*G, v2);
			
			if(!i || !j)			 //保证获取的顶点存在
				return 0;
			
			/*v1->v2*/
			p = (ArcNode *)malloc(sizeof(ArcNode));
			if(!p)
				exit(0);
			p->adjvex = j;      //顶点v2的序号为j 
			p->nextarc = NULL;
			
			if(r[i]==NULL)	 //说明还没有边与顶点v1相连
				(*G).vertices[i].firstarc = p;	//加入到邻接表 
			else
				r[i]->nextarc = p;	//令p连接到当前顶点边链表最后一个结点后面
			r[i] = p; //r[i]指向当前顶点边链表最后一个结点的位置
	
			/*v2->v1*/
			q = (ArcNode *)malloc(sizeof(ArcNode));
			if(!q)
				exit(0);
			q->adjvex = i;   //顶点v1的序号为i
			q->nextarc = NULL;
			
			if(r[j]==NULL)		//说明还没有边与顶点v2相连 
				(*G).vertices[j].firstarc = q;		//加入到邻接表 
			else
				r[j]->nextarc = q;			
			r[j] = q;
		}
		
		return 1;
	}
	
	/*输出图*/
	void OutputALGraph(ALGraph G){
		int i, j;
		ArcNode *p;
		
		if(!G.vexnum && !G.arcnum)
			printf("空图(表)!\n");
		else{
			for(i=1; i<=G.vexnum; i++){
				printf("%d→", G.vertices[i].data);
				p = G.vertices[i].firstarc;
				while(p){
					printf(" %d", G.vertices[p->adjvex].data);
					p = p->nextarc;
				}
				printf("\n");	
			}
		}
	}
	
	/*展示染色结果*/
	void showResult(ALGraph G){
		int i, j;
		ArcNode *p;
		
		if(!G.vexnum && !G.arcnum)
			printf("空图(表)!\n");
		else{
			for(i=1; i<=G.vexnum; i++){
				printf("区域%d→→颜色%d\n", G.vertices[i].data, G.vertices[i].color);	
			}
		}
	}
	
	/*判断与序号为nodeOrder的顶点直接相邻的边是否有相同的颜色,若有,说明此方案不行*/
	int isColorOK(ALGraph G, int nodeOrder) { 
		ArcNode *p =G.vertices[nodeOrder].firstarc;
		while(p){
			if(G.vertices[nodeOrder].color == G.vertices[p->adjvex].color)
				return 0;
			p = p->nextarc;
		}
		return 1;
	}
	
	/*回溯法对图着色【此题与八皇后问题神似】*/
	/*展示所有符合条件的解*/
	int getColorPowset(ALGraph *G, int colorNum, int step){  
		int i;
		if(step > (*G).vexnum){ //如果step>(*G).vexnum,说明所有顶点的染色都符合条件,它们都已被染色
			printf("地图染色问题的第 %d 种解法...\n", ++order);
			showResult(*G); //展示染色结果
		}	
		else{
			for(i = 1; i<=colorNum; i++){
				(*G).vertices[step].color = i; //先在vertices[step]处染上颜色i
				/*判断能否在vertices[step]处染色【即判断该顶点四周有没有相同的颜色】*/
				if(isColorOK(*G, step)) //若可以
					getColorPowset(G, colorNum, step+1); //到下一个顶点染色
				/*
				两种情况:
				1、vertices[step]处不能染成i颜色【不符合染色条件】
				2、vertices[step]处可以染成i颜色,但由于vertices[step+1]处无法放置符合条件的颜色,退回到这里,因此vertices[step]处放i颜色不合适,它不能放这里,否则vertices[step+1]处无法合理染色
				总之:要将vertices[step]处染的颜色i去掉【回朔】,然后再次进入for循环,换其它颜色染vertices[step]
				*/
				(*G).vertices[step].color = None; //回朔
			}
		}
		return 0;
	}
	
	int main(){
		ALGraph G;
		FILE *fp;
		int vex, tarColor;
		printf("创建无向图...\n");
		fp = fopen("2015-08-02_UDG_AL.txt", "r");
		CreateUDG(fp, &G); 
		fclose(fp);
		printf("\n");
		printf("输出图的邻接表 G = \n");		
		OutputALGraph(G);
	
		printf("染色区域:1,2,3,4,5\n");
		printf("可染颜色:1【红】,2【绿】,3【蓝】,4【黄】\n");
		/*颜色的种类是4,刚开始从vertices[1]开始试探*/
		printf("所有染色方案如下:\n");
		getColorPowset(&G, 4, 1);
	
		return 1;
	}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值