看前须知
第七次上机题汇总
最少布线(图)——Prim(BFS+贪心)+kruskal(并查集)双解法+原理解释.
北京地铁乘坐线路查询——Dijkstra和Floyd双解法.
题目内容
问题描述
老张和老王酷爱爬山,每周必爬一次香山。有次两人为从东门到香炉峰共有多少条路径发生争执,于是约定一段时间内谁走过对方没有走过的路线多谁胜。
给定一线路图(无向连通图,两顶点之间可能有多条边),编程计算从起始点至终点共有多少条独立路径,并输出相关路径信息。
注:独立路径指的是从起点至终点的一条路径中至少有一条边是与别的路径中所不同的,同时路径中不存在环路。
输入形式
图的顶点按照自然数(0,1,2,…,n)进行编号,其中顶点0表示起点,顶点n-1表示终点。从标准输入中首先输入两个正整数n,e,分别表示线路图的顶点的数目和边的数目,然后在接下的e行中输入每条边的信息,具体形式如下:
< n > < e >
< e1 > < vi1 > < vj1 >
< e2 > < vi2 > < vj2 >
…
< en > < vin > < vjn >
说明:第一行< n>为图的顶点数,< e>表示图的边数;第二行< e1> < vi1> < vj1>分别为边的序号(边序号的范围在[0,1000)之间,即包括0不包括1000)和这条边的两个顶点(两个顶点之间有多条边时,边的序号会不同),中间由一个空格分隔;其它类推。
输出形式
输出从起点0到终点n-1的所有路径(用边序号的序列表示路径且路径中不能有环),每行表示一条由起点到终点的路径(由边序号组成,中间有一个空格分隔,最后一个数字后跟回车),并且所有路径按照字典序输出。
样例
【样例输入】
6 8
1 0 1
2 1 2
3 2 3
4 2 4
5 3 5
6 4 5
7 0 5
8 0 1
【样例输出】
1 2 3 5
1 2 4 6
7
8 2 3 5
8 2 4 6
样例说明
样例输入构成的图如下:
输出的第一个路径1 2 3 5,表示一条路径,先走1号边(顶点0到顶点1),然后走2号边(顶点1到顶点2),然后走3号边(顶点2到顶点3),然后走5号边(顶点3到顶点5)到达终点。
题解
思考和详解
这道题难度一般,主要考察图中的搜索与回溯,置于选择的搜索方式,建议选择深度优先搜索(DFS),这道题与遍历的题的不同之处在于搜索结束的条件不同,前者要求的是访问数组visited全不为0,而后者则是要求搜索到的顶点编号与要求的相同。
本题最容易的忽略之处在于回溯,如果对于DFS+回溯还不太熟悉的话,建议先回顾一下之前的全排列,我在这一题的题解上做了超级详细的解释和说明( 点击此处回顾全排列DFS+回溯.),如果回溯没有问题,这道题就迎刃而解了。
参考代码
#include<stdio.h>
#include<stdlib.h>
typedef struct edge{
int pathID; //路径编号
int adjvex; //另一端点的位置
int weight; //权重
struct edge *next;
}Enode,*Enodep;
typedef struct ver{
int vertex; //顶点信息
Enode *next; //Enode的第一个节点
}Vnode,*Vnodep;
Vnode G[2000];
int visited[2000]={0},Path[2000],Vnum,Enum,depth=0,vBegin,vEnd,pathID;
Enodep insertEdge(Enodep head, int pathID, int num); //录入边信息(包含路径编号和路径尾端顶点标号)
void printPathID(int n); //打印路径
void DFSgraph(int v, int depth); //DFS深度优先遍历图 (内含回溯算法 )
int main()
{
int i,v1,v2;
scanf("%d %d",&Vnum,&Enum); //输入顶点总数和边总数
vBegin=0,vEnd=Vnum-1; //DFS开始节点的编号和 DFS终止节点编号
for(i=0;i<Enum;i++)
{
scanf("%d %d %d",&pathID,&v1,&v2); //录入信息
G[v1].next=insertEdge(G[v1].next,pathID,v2); //构造图的邻接表形式
G[v2].next=insertEdge(G[v2].next,pathID,v1); //构造图的邻接表形式
}
visited[vBegin]=1; //开始节点已经用过
DFSgraph(vBegin,depth); //开始 DFS遍历
return 0;
}
Enodep insertEdge(Enodep head, int pathID, int num)
{
Enodep e,p;
e=(Enodep)malloc(sizeof(Enode));
e->pathID=pathID,e->adjvex=num,e->weight=1,e->next=NULL; //录入信息
if(head==NULL) //构造头节点
{
head=e;
return head;
}
else
{
for(p=head;p->next!=NULL;p=p->next)
;
p->next=e; //插入节点
return head;
}
}
void printPathID(int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%d ",Path[i]); //输入路径上的节点ID
}
puts("");
}
void DFSgraph(int v, int depth)
{
Enodep p;
if(v==vEnd) //终止条件:遍历到终止节点ID
{
printPathID(depth); //打印路径节点信息
return;
}
for(p=G[v].next;p!=NULL;p=p->next)
{
if(!visited[p->adjvex]) //如果临节点没有被访问过
{
Path[depth]=p->pathID; //录入节点信息
visited[p->adjvex]=1; //已访问
DFSgraph(p->adjvex,depth+1); //继续 DFS
visited[p->adjvex]=0; //*************注意要回溯
}
}
}
补充测试的数据
【样例输入】
6 10
1 0 1
2 0 2
3 0 3
4 1 2
5 1 4
6 1 5
7 2 4
8 4 5
9 2 3
10 3 4
【样例输出】
1 4 7 8
1 4 9 10 8
1 5 8
1 6
2 4 5 8
2 4 6
2 7 5 6
2 7 8
2 9 10 5 6
2 9 10 8
3 9 4 5 8
3 9 4 6
3 9 7 5 6
3 9 7 8
3 10 5 6
3 10 7 4 6
3 10 8