在有向完全图中,每两个不同的顶点之间都有两条方向相反的弧(从顶点u到顶点v和从顶点v到顶点u)。
对于 n 个顶点的有向完全图,弧数的计算公式为:弧数=n×(n−1)


DFS 遍历顺序取决于邻接点的访问顺序,v0 的邻接点有 3 个,排列组合共 3! = 6 种,但部分排列会生成相同序列

\(a, b, c, e, d\) \(a, e, b, c, d\) \(a, e, c, b, d\)

Prim 算法是从一个顶点开始,不断添加与已选顶点集关联的最小权值边来扩展生成树;Kruskal 算法是从权值最小的边开始,不断添加不构成回路的边来构建生成树。对于一些图,使用这两种算法得到的最小生成树可能是相同的。

Dijkstra 算法用于求解图中某一特定顶点到其他各顶点的最短路径,采用贪心策略,每次选择距离源点最近且未确定最短路径的顶点。
若用邻接矩阵存储有向图,矩阵中主对角线以下的元素均为零,则关于该图拓扑序列的结论是(存在,可能不唯一 )



在 AOE 网(边表示活动的网)中,关键路径决定了整个工程的工期,只有加快关键路径上活动的进度,才可能缩短工程工期。
确定关键路径:计算各事件的最早发生时间ve和最迟发生时间vl。事件的最早发生时间ve是从源点到该事件的最长路径长度;事件的最迟发生时间vl是在不影响整个工程工期的前提下,该事件最迟发生的时间。对于活动i,若其开始事件为j,结束事件为k,活动持续时间为wjk,则活动i的最早开始时间e(i)=ve(j),最迟开始时间l(i)=vl(k)−wjk。当e(i)=l(i)时,该活动是关键活动,由关键活动组成的路径就是关键路径。

已知无向连通图G中各边的权值均为1。在下列算法中,一定能够求出图 G中从某顶点到其余各顶点最短路径的是(仅III )。
I. Prim 算法 II. Kruskal 算法 III. 图的广度优先搜索算法
图的创建(邻接矩阵)
本题要求建立一个无向图,采用邻接矩阵做为存储结构。
int locate(MGraph G,char v)//返回顶点v的下标
{
int i;
for(i=0;i<G.vexnum;i++)
if(G.vexs[i]==v)
return i;
return -1;
}
void CreatMGraph(MGraph &G)
{
int i,j,k;
char v1,v2;
scanf("%d%d",&G.vexnum,&G.arcnum);
getchar();
for(i=0;i<G.vexnum;i++)
scanf("%c",&G.vexs[i]);
for(i=0;i<G.vexnum;i++)
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=0;
for(k=0;k<G.arcnum;k++) {
getchar();
scanf("%c%c",&v1,&v2);
i=locate(G,v1);
j=locate(G,v2);
G.arcs[i][j] = 1;
G.arcs[j][i] = 1;
}
}
图的创建-邻接表
本题要求建立一个无向图,采用邻接表做为存储结构。
int locate(ALGraph G,char v);
void CreatMGraph(ALGraph &G) {
int i, j, k;
ArcNode *p;
char v1, v2;
// 输入顶点数和边数
scanf("%d %d", &G.vexnum, &G.arcnum);
getchar(); // 消耗掉换行符
// 输入顶点信息,初始化头结点数组
for (i = 0; i < G.vexnum; i++) {
scanf("%c", &G.vertices[i].data);
G.vertices[i].firstarc = NULL;
}
getchar(); // 消耗掉换行符
// 输入边的信息,建立邻接表
for (k = 0; k < G.arcnum; k++) {
v1 = getchar();
v2 = getchar();
getchar(); // 消耗掉换行符
// 查找顶点v1和v2的位置
int i, j;
for (i = 0; i < G.vexnum; i++) {
if (G.vertices[i].data == v1) break;
}
for (j = 0; j < G.vexnum; j++) {
if (G.vertices[j].data == v2) break;
}
// 生成一个新的表结点
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = j; // 邻接点序号为j
// 将新结点插入到顶点vi的边表头部
p->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p;
// 若是无向图,还需生成一个对称的边
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = i; // 邻接点序号为i
// 将新结点插入到顶点vj的边表头部
p->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p;
}
}
孤勇者探险(图的遍历)
一款名为“孤勇者探险”的游戏,游戏中共有若干个小岛,每个岛上均有怪兽,闯关者打倒岛上的怪兽则可获得该岛对应的游戏积分(每个岛的积分根据难度可能不相同),编写程序求出最终闯关成功者(闯过所有小岛)共获得多少积分,并给出对应的闯关行进路线。
思路提示:
游戏地图可抽象为图结构,且一定为连通图。图中顶点的值则为每个小岛对应的积分,‘0’小岛为起点,从0号开始遍历,将各个顶点的值累加则为最终获得得分,同时输出遍历序列,则为对应的闯关行进路线。
void CreateUDG(AMGraph &G)
{
int i=0;
int j;
scanf("%d",&G.vexs[i]);
G.vexnum=0;
while(G.vexs[i]!=-1)
{
i++;
scanf("%d",&G.vexs[i]);
G.vexnum++;
}
for(i=0;i<G.vexnum ;i++)
{
for(j=0;j<G.vexnum;j++)
{
G.arcs[i][j]=0;
}
}
int v1,v2;
G.arcnum=0;
scanf("%d %d",&v1,&v2);
while((v1 != -1) && (v2 != -1))
{
G.arcs[v1][v2]=1;
G.arcs[v2][v1]=G.arcs[v1][v2];
G.arcnum++;
scanf("%d %d",&v1,&v2);
}
}
int DFS(AMGraph G, int v)
{
int cnt=0;
printf("%d ",G.vexs[v]);
cnt+=G.vexs[v];
visited[v]=1;
int i;
int k=0;
for(i=0;i<G.vexnum;i++)
{
if((G.arcs[v][i]!=0) && (!visited[i]))
{
k=DFS(G,i);
cnt+=k;
}
}
return cnt;
}
图的广度遍历-邻接表实现
void BFS(ALGraph *G, int v) {
int queue[MAX_VERTEX_NUM];
int front = 0, rear = 0;
visited[v] = TRUE;
queue[rear++] = v;
while (front < rear) {
int u = queue[front++];
printf(" %d", u);
ArcNode *p = G->vertices[u].firstarc;
while (p != NULL) {
int w = p->adjvex;
if (!visited[w]) {
visited[w] = TRUE;
queue[rear++] = w;
}
p = p->nextarc;
}
}
}
判断是否唯一拓扑序列(408)
请设计算法:int uniquely(MGraqh G),判定 G 是否存在唯一的拓扑序列,若是,则返回 1, 否则返回0。
#include <stdlib.h>
int uniquely(MGraph G) {
int inDegree[MVNum] = {0};
int queue[MVNum];
int front = 0, rear = 0;
int count = 0;
// 计算每个顶点的入度
for (int j = 0; j < G.vexnum; j++) {
for (int i = 0; i < G.vexnum; i++) {
if (G.arcs[i][j] == 1) {
inDegree[j]++;
}
}
}
// 初始化队列,将入度为0的顶点入队
for (int i = 0; i < G.vexnum; i++) {
if (inDegree[i] == 0) {
queue[rear++] = i;
}
}
while (front < rear) {
// 若队列中元素数量超过1,说明拓扑序列不唯一
if (rear - front > 1) {
return 0;
}
int u = queue[front++];
count++;
// 减少邻接顶点的入度,并将入度变为0的顶点入队
for (int v = 0; v < G.vexnum; v++) {
if (G.arcs[u][v] == 1) {
inDegree[v]--;
if (inDegree[v] == 0) {
queue[rear++] = v;
}
}
}
}
// 若拓扑排序无法包含所有顶点,说明图中存在环
if (count != G.vexnum) {
return 0;
}
return 1;
}
最小生成树(普里姆算法)
#include <iostream>
#define MVNum 100
#define MaxInt 32767
using namespace std;
struct edge{
char adjvex;
int lowcost;
}closedge[MVNum];
typedef struct{
char vexs[MVNum];
int arcs[MVNum][MVNum];
int vexnum,arcnum;
}AMGraph;
int LocateVex(AMGraph G , char v);//实现细节隐藏
int CreateUDN(AMGraph &G);//实现细节隐藏
int Min(AMGraph G){
int i;
int index = -1;
int min = MaxInt;
for(i = 0 ; i < G.vexnum ; ++i){
if(closedge[i].lowcost != 0 && closedge[i].lowcost < min){
min = closedge[i].lowcost;
index = i;
}
}
return index;
}
void MiniSpanTree_Prim(AMGraph G, char u){
int k , j , i;
char u0 , v0;
k =LocateVex(G, u);
for(j = 0; j < G.vexnum; ++j){
if(j != k){
closedge[j].adjvex =u ;
closedge[j].lowcost = G.arcs[k][j];
}
}
closedge[k].lowcost = 0;
for(i = 1; i < G.vexnum; ++i){
k = Min(G);
u0 = closedge[k].adjvex;
v0 = G.vexs[k];
cout << u0 << "->" << v0 << endl;
closedge[k].lowcost =0 ;
for(j = 0; j < G.vexnum; ++j)
if(G.arcs[k][j] < closedge[j].lowcost){
closedge[j].adjvex = G.vexs[k];
closedge[j].lowcost = G.arcs[k][j];
}
}
}
int main(){
AMGraph G;
CreateUDN(G);
char u;
cin >> u;
MiniSpanTree_Prim(G , u);
return 0;
}
最短路径(迪杰斯特拉算法)。
typedef char VerTexType;
typedef int ArcType;
int *D=new int[MVNum];
bool *S=new bool[MVNum];
int *Path=new int[MVNum];
typedef struct{
VerTexType vexs[MVNum];
ArcType arcs[MVNum][MVNum];
int vexnum,arcnum;
}AMGraph;
int LocateVex(AMGraph G , VerTexType v)//该实现细节隐藏
void CreateUDN(AMGraph &G);//该实现细节隐藏
void ShortestPath_DIJ(AMGraph G, int v0){
int v , i , w , min;
int n = G.vexnum;
for(v = 0; v < n; ++v){
S[v] = false;
D[v] = G.arcs[v0][v];
if(D[v] < MaxInt) Path [v] = v0;
else Path [v] = -1;
}
S[v0]=true;
D[v0]=0;
for(i = 1;i < n; ++i){
min= MaxInt;
for(w = 0; w < n; ++w)
if(!S[w] && D[w] < min){
v = w;
min = D[w];
}
S[v]=true;
for(w = 0;w < n; ++w)
if(!S[w] && G.arcs[v][w] != MaxInt &&D[v] + G.arcs[v][w] < D[w]){
D[w] = D[v] + G.arcs[v][w];
Path [w] = v;
}
}
}
void DisplayPath(AMGraph G , int begin ,int temp ){
if(Path[temp] != -1){
DisplayPath(G , begin ,Path[temp]);
cout << G.vexs[Path[temp]] << "->";
}
}
int main()
{
AMGraph G;
int i , j ,num_start , num_destination;
VerTexType start , destination;
CreateUDN(G);
cin >> start >> destination;
num_start = LocateVex(G , start);
num_destination = LocateVex(G , destination);
ShortestPath_DIJ(G , num_start);
DisplayPath(G , num_start , num_destination);
cout << G.vexs[num_destination]<<endl;
return 0;
}