- 邻接矩阵的操作
#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;
}
- 邻接表的操作
建立图的邻接表,需要知道的信息包括图的顶点数、边数以及各边的起点与终点序号。
有向图与无向图处理方法不同:对于无向图,一条边的两个顶点 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的结点
已补上。