图的基本操作03

  1. 邻接矩阵的操作
#include<stdio.h>
#include<stdlib.h>
#define VERTEX_NUM 64
typedef struct
{   char  VertexArray[VERTEX_NUM];  //顶点数组
    int   AdjMatrix[VERTEX_NUM][ VERTEX_NUM];  //邻接矩阵
    int  VexNum, EdgeNum;
} AM_Graph;

/*=======================================
函数功能:无向图邻接矩阵的建立
函数输入:邻接矩阵空间地址
函数输出:无
键盘输入:顶点值、边的关联顶点
=========================================*/
void creat_AdjMatrix(AM_Graph *gPtr)
{
	int i,j,k;
	getchar();
	printf("请输入%d个顶点:",gPtr->VexNum);
	for(i=0;i<gPtr->VexNum;i++)
		scanf("%c",&gPtr->VertexArray[i]);
	for(i=0;i<gPtr->VexNum;i++)
		for(j=0;j<gPtr->VexNum;j++)
			gPtr->AdjMatrix[i][j]=0;
		printf("输入邻接的两个顶点下标:\n");
		for(k=0;k<gPtr->EdgeNum;k++)
		{
			scanf("%d%d",&i,&j);
			gPtr->AdjMatrix[i][j]=1;
			gPtr->AdjMatrix[j][i]=1;
		}
}

/*=======================================
函数功能:无向图邻接矩阵的输出
函数输入:邻接矩阵空间地址
函数输出:无
屏幕输出:邻接矩阵
=========================================*/
void print_AdjMatrix(AM_Graph *gPtr) 
{
	int i,j;
	printf("建立好后的无向图的邻接矩阵为:\n");
	for(i=0;i<gPtr->VexNum;i++)
	{
		printf("%c  ",gPtr->VertexArray[i]);
	for(j=0;j<gPtr->VexNum;j++)
	   printf("%d  ",gPtr->AdjMatrix[i][j]);
	printf("\n");
	}
}

int main()
{ 
AM_Graph Graph;

       printf("请输入顶点数和边数:");
	   scanf("%d%d",&Graph.VexNum, &Graph.EdgeNum);
	   creat_AdjMatrix(&Graph);
	   print_AdjMatrix(&Graph);
	  return 0; 
}
  1. 邻接表的操作
    建立图的邻接表,需要知道的信息包括图的顶点数、边数以及各边的起点与终点序号。
    有向图与无向图处理方法不同:对于无向图,一条边的两个顶点 v1、v2 互为临接点。存储时,向起点 v1 的单链表表头插入一边结点,即终点 v2;然后将终点 v2 的单链表表头插入一边结点,即起点 v1.对于有向图,向起点 v1 的单链表的表头插入一个边结点,即终点 v2 。
    在这里插入图片描述
#include<stdio.h>
#include<stdlib.h>
#define  VERTEX_NUM  6        	//图的顶点数
#define  VERTEX_MAX_NUM 10   	//图的最大顶点数
#define  EDGE_MAX_NUM  20   		//图的最大边数
typedef char VexType;  				//顶点的数据类型
typedef int InfoType;   				//弧(边)的相关信息类型,如权值、边存在或不存在等

typedef struct AdjNode  				//邻接结点结构
{     
   int adjvex;        				//邻接点
   AdjNode *next;   				//邻接点指针
} AL_AdjNode; 

typedef struct  						//邻接表顶点结点结构
{             
   VexType  vertex;   				//顶点
   AdjNode *link;     				//邻接点头指针
} AL_VexNode; 

typedef struct  						//总的邻接表结构
{                 
   AL_VexNode  VexList[VERTEX_MAX_NUM]; //顶点表
   int VexNum, ArcNum;    			//顶点数,弧(边)数
} AL_Graph; 

/*================================
函数功能:建立有向图的邻接表结构
函数输入:无
函数输出:邻接表
键盘输入:图的顶点数、边数、边信息
================================*/
AL_Graph *Create_AdjList()
{         
   int n,e,i,v1,v2; 
   AL_AdjNode * AdjPtr;    			//定义邻接结点指针
   AL_Graph *alPtr;   				//定义邻接表指针
   alPtr=(AL_Graph *)malloc(sizeof(AL_Graph)); 	//申请总的邻接表空间
   printf("请输入图的顶点数:\n"); 
   scanf("%d",&n);    				//输入顶点数
   for(i=0;i<=n;i++)					//初始化邻接表空间
   { 
       alPtr->VexList[i].vertex=(char)i; 	//给头结点赋值
       alPtr->VexList[i].link=NULL;   	//初始化头结点
   } 
    printf("请输入边数:\n"); 
    scanf("%d",&e);   				//输入边的数目 
    printf("请输入弧的信息:\n"); 
    for(i=0;i<e;i++)
	{ 
        printf("请输入弧的两个端点,第一个为弧头,第二个为弧尾\n");
        scanf("%d%d",&v1,&v2);    	//输入边的两个结点
        AdjPtr =(AL_AdjNode *)malloc(sizeof(AL_AdjNode));  //申请新邻接结点
        AdjPtr->adjvex=v2;      		//v2做新邻接点编号
        AdjPtr->next=alPtr->VexList[v1].link;  	//新邻接点链入v1为顶点的邻接链表表头
        alPtr->VexList[v1].link=AdjPtr;  	 //使头结点指向新结点
    } 
    alPtr->VexNum=n;     			//将顶点数n给alPtr->VexNum
    alPtr->ArcNum=e;     			//将边数e给alPtr->ArcNum
    return alPtr;   					//返回该邻接表
} 
/*================================
函数功能:输出邻接表到屏幕
函数输入:邻接表地址
函数输出:无
=================================*/
void Print_AdjList(AL_Graph *algPtr)
{     
    int i; 
    AL_AdjNode *AdjPtr;     
    printf("图的邻接表\n"); 
    for(i=0;i<algPtr->VexNum;i++)		//当在结点个数范围内时
	{     
//输出顶点表中第i个顶点的值       
printf("%d-",algPtr->VexList[i].vertex);          
        							//取第i个邻接链表的首地址
AdjPtr=algPtr->VexList[i].link;   
        while(AdjPtr!=NULL)			//邻接链表非空
		{     
            printf("%d-",AdjPtr->adjvex);	//输出邻接结点
            AdjPtr=AdjPtr->next;    	//取下一个邻接结点地址
 		} 
        printf("--\n"); 
    } 
} 
int main()
{ 
    AL_Graph *gPtr;
    gPtr=Create_AdjList();
    Print_AdjList(gPtr);
    return 0; 
}

考试安排问题
通信工程学院有9门课要期中考试,不能同时考试的课程在集合R中表示,其中括号里的一对数表示相应的课程考试有冲突,如何安排,让考试无冲突且考试的天数最少?
课程编号={1, 2, 3, 4, 5, 6, 7, 8, 9}
冲突课程R={(2, 8), (9, 4), (2, 9), (2, 1), (2, 5), (6, 2), (5, 9), (5, 6), (5, 4), (7, 5), (7, 6), (3, 7), (6, 3)}

分析:
从课程与课程间的冲突可以观察出,课程可以对应图的顶点集合,课程间的关系可以对应图的边的集合,因此,可以把问题中的信息及其联系用图表示出来。一条边两端的顶点有冲突,可以用不同的颜色标示出来,这样考试的安排问题就转化为图的染色问题了——用尽可能少的颜色给该图的每个顶点着色,使相邻的顶点着上不同的颜色。
若按照 degree 由大到小排序,然后一一涂色,每一个点都先尝试涂第一种颜色,若与已涂色的点有冲突,则换另一种颜色,直到颜色不冲突为止,这种图的染色算法即 Welsh-Powell(韦尔奇*鲍威尔)法。

算法描述
在这里插入图片描述
伪代码描述一
在这里插入图片描述
伪代码描述二
在这里插入图片描述
数据结构设计

相同颜色的顶点放在一个数组 node 里,数组长度最大为 N ,数组已有顶点的最后位置由尾指针 rear 记录。颜色集 ColorSet 中颜色数最多也为 N,即每个顶点的颜色不一样。每种颜色是否被用由 used 标记,设 0 为未用,1 为已用。
在这里插入图片描述

struct ColorNode
{
     int used; // 标记颜色是否被用,0代表未用
     int rear; //集合尾指针
     int node[N];//同色顶点集合
} ColorSet[N] //颜色集 

程序实现

#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define N 9 				//顶点数
int AdjMatrix[N][N]= {		//邻接矩阵
	{0,1,0,0,0,0,0,0,0},
	{1,0,0,0,1,1,0,1,1},
	{0,0,0,0,0,1,1,0,0},
	{0,0,0,0,1,0,0,0,1},
	{0,1,0,1,0,1,1,0,1},
	{0,1,1,0,1,0,1,0,0},
	{0,0,1,0,1,1,0,0,0},
	{0,1,0,0,0,0,0,0,0},
	{0,1,0,1,1,0,0,0,0}
};
int degree[N]= {0};  					//记录顶点的degree数目
char *color[N]= {"红","橙","黄","绿","青","蓝","紫","黑","白"};

struct ColorNode {
	int used; 						//标记颜色是否被用,0代表未用
	int rear; 						//顶点集合尾指针
	int node[N];					//同色顶点集合
} ColorSet[N]= {{0,0,0,0}};	//颜色集
/*============================
函数功能:找度最大的结点下标
函数输入:顶点度数组
函数输出:度最大的结点下标
=============================*/
int FindMax(int *a) {
	int i,value,index;
	value=-1;
	index=0;
	for(i=0; i<N; i++) {
		if(value < a[i]) {
			value=a[i];
			index=i;
		}
	}
	a[index]=-1;					//清除当前最大值
	return index;
}

/*=========================================
函数功能:判断k点是否能加入颜色集中第i种颜色顶点集
函数输入:第i种颜色,k结点
函数输出:1——可以加入
          0——不能加入
==========================================*/
int judge(int i,int k) {
	int p,q,m;

	p=0;
	q=ColorSet[i].rear;
	m=ColorSet[i].node[p];			//颜色集中下标为p的结点
	//k、p不是邻接点且p不是颜色集中的最后一个结点
	while (AdjMatrix[k][m]==0 && p!=ColorSet[i].rear) { //条件二判断ColorSet的node不为空且结束在集合中查找
		p++;
		m=ColorSet[i].node[p];			//颜色集中下标为p的结点
	}
	if (p==q)return 1;				//k可以加入颜色集
	return 0;						//k不能加入颜色集
}

/*=========================================
函数功能:Welsh_Powell图结点染色法
函数输入:无
函数输出:无
屏幕输出:同色结点集合
==========================================*/
void Welsh_Powell() {
	int i,k;
	int colorPtr;

	//计算顶点的degree
	for (i=0; i<N; ++i) {
		for (int j=0; j<N; ++j) {
			if (i != j && AdjMatrix[i][j])
				degree[i]++;
		}
	}

	for (int j=0; j<N; ++j) {
		k=FindMax(degree);//找度最大结点k
		colorPtr=0;
		//colorPtr项颜色已经使用过
		if(	ColorSet[colorPtr].used==1) {
			while(!judge(colorPtr,k))//若k不能加入colorPtr项的颜色集
				colorPtr++;
		}
		//将k加入colorPtr项颜色集
		ColorSet[colorPtr].node[ColorSet[colorPtr].rear++]=k;
		if(	ColorSet[colorPtr].used==0) ColorSet[colorPtr].used=1;
	}
	//输出同色结点集合
	for (int j=0; j<N; ++j) {
		if (ColorSet[j].used==1) {
			printf("%s:",color[j]);
			for (i=0; i<ColorSet[j].rear; ++i)
				printf("%d ",ColorSet[j].node[i]+1);
			printf("\n");
		}
	}
}
int main() {
	Welsh_Powell();
	return 0;
}

在FindMax 函数中漏掉一条 m=ColorSet[i].node[p]; //颜色集中下标为p的结点

已补上。

发布了26 篇原创文章 · 获赞 3 · 访问量 1464

猜你喜欢

转载自blog.csdn.net/herui7322/article/details/104358860