A - 数据结构实验之图论一:基于邻接矩阵的广度优先搜索遍历
Description
给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列。(同一个结点的同层邻接点,节点编号小的优先遍历)
Input
输入第一行为整数n(0< n <100),表示数据的组数。
对于每组数据,第一行是三个整数k,m,t(0<k<100,0<m<(k-1)*k/2,0< t<k),表示有m条边,k个顶点,t为遍历的起始顶点。
下面的m行,每行是空格隔开的两个整数u,v,表示一条连接u,v顶点的无向边。
Output
输出有n行,对应n组输出,每行为用空格隔开的k个整数,对应一组数据,表示BFS的遍历结果。
Sample
Input
1
6 7 0
0 3
0 4
1 4
1 5
2 3
2 4
3 5
Output
0 3 4 2 5 1
Hint
以邻接矩阵作为存储结构。
简单存储领接矩阵实现
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int map[101][101];
int ans[101];
int temp[101];
int k = 0;
void BFS(int n)
{
int front,rear,start;
front = rear = 0;
ans[n]=1;
temp[rear++] = n;
while(rear>front){
start = temp[front++];
for(int i=0;i<k;i++){
if(!ans[i] && map[start][i]){
ans[i] = 1;
temp[rear++] = i;
}
}
}
}
int main()
{
int t,m,T,x,y;
scanf("%d",&T);
while(T--){
memset(map,0,sizeof(map));
memset(temp,0,sizeof(temp));
memset(ans,0,sizeof(ans));
scanf("%d%d%d",&k,&m,&t);
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
map[x][y]=1;
map[y][x]=1;
}
BFS(t);
for(int i=0;i<k;i++){
if(i<k-1){
printf("%d ",temp[i]);
}
else{
printf("%d\n",temp[i]);
}
}
}
return 0;
}
正规邻接矩阵做法
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define INF INT_MAX
#define MAXVEX 30
typedef char vertextype[10];
typedef struct vertex
{
int adjvex;
vertextype data;
}Vtype;
typedef struct graph
{
int n;
int e;
Vtype vexs[MAXVEX];
int edges[MAXVEX][MAXVEX];
}Mgraph;
void creategraph(Mgraph &g,int map[][MAXVEX],int n1,int n2)
{
g.n = n1;
g.e = n2;
for(int i=0;i<g.n;i++){
for(int j=0;j<g.n;j++){
g.edges[i][j] = map[i][j];
}
}
}
void BFS(Mgraph &g,int t)
{
int rear,front,start,vis[MAXVEX];
rear=front= 0;
for(int i=0;i<MAXVEX;i++){
vis[i] = 0;
}
vis[t] = 1;
g.vexs[rear++].adjvex = t;
while(rear>front){
start = g.vexs[front++].adjvex;
for(int i=0;i<g.n;i++){
if(!vis[i] && g.edges[start][i]==1){
vis[i] = 1;
g.vexs[rear++].adjvex = i;
}
}
}
}
int main()
{
int T,n,e,t,x,y;
int map[MAXVEX][MAXVEX];
scanf("%d",&T);
while(T--){
Mgraph g;
scanf("%d%d%d",&n,&e,&t);
for(int i=0;i<e;i++){
scanf("%d%d",&x,&y);
map[x][y] = 1;
map[y][x] = 1;
}
creategraph(g,map,n,e);
BFS(g,t);
for(int i=0;i<g.n;i++){
if(i<g.n-1){
printf("%d ",g.vexs[i].adjvex);
}
else{
printf("%d\n",g.vexs[i].adjvex);
}
}
}
return 0;
}
数据结构实验之图论二:基于邻接表的广度优先搜索遍历
Description
给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列。(同一个结点的同层邻接点,节点编号小的优先遍历)
Input
输入第一行为整数n(0< n <100),表示数据的组数。
对于每组数据,第一行是三个整数k,m,t(0<k<100,0<m<(k-1)*k/2,0< t<k),表示有m条边,k个顶点,t为遍历的起始顶点。
下面的m行,每行是空格隔开的两个整数u,v,表示一条连接u,v顶点的无向边。
Output
输出有n行,对应n组输出,每行为用空格隔开的k个整数,对应一组数据,表示BFS的遍历结果。
Sample
Input
1
6 7 0
0 3
0 4
1 4
1 5
2 3
2 4
3 5
Output
0 3 4 2 5 1
Hint
用邻接表存储。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define INF INT_MAX
#define MAXVEX 10
int temp[MAXVEX];
int top = 0;
typedef struct edgenode
{
int adjvex;/*相邻点序号*/
int weight;/*边的权值*/
edgenode *nextarc;/*下一条边的信息*/
}ArcNode;/*边结点类型*/
typedef struct vexnode
{
int data;/*顶点的信息*/
ArcNode *firstarc;/*头结点,指向第一条边结点*/
}VheadNode;/*头结点类型*/
typedef struct graph
{
int vernums;
int edgenums;
VheadNode adjlist[MAXVEX];/*单链表头结点数组*/
}Mgraph;
void creategraph(Mgraph &G,int n1,int n2)
{
int u,v;
G.vernums = n1;
G.edgenums = n2;
for(int i=0;i<G.vernums;i++){
G.adjlist[i].data = i;
G.adjlist[i].firstarc=NULL;
}
ArcNode *s,*p;
for(int i=0;i<G.edgenums;i++){
scanf("%d%d",&u,&v);
s=(ArcNode*)malloc(sizeof(ArcNode));
s->adjvex=v;
p=G.adjlist[u].firstarc;
if(!p){
s->nextarc = NULL;
G.adjlist[u].firstarc = s;
}
else{
while(p->nextarc){
p=p->nextarc;
}
s->nextarc = p->nextarc;
p->nextarc = s;
}
s=(ArcNode*)malloc(sizeof(ArcNode));
s->adjvex=u;
p=G.adjlist[v].firstarc;
if(!p){
s->nextarc = NULL;
G.adjlist[v].firstarc = s;
}
else{
while(p->nextarc){
p=p->nextarc;
}
s->nextarc = p->nextarc;
p->nextarc = s;
}
}
}
void BFS(Mgraph &g,int t)
{
ArcNode *p;
int front,rear,start;
int vis[MAXVEX],Queue[MAXVEX];
front = rear = 0;
for(int i=0;i<MAXVEX;i++){
vis[i] = 0;
}
vis[t] = 1;
temp[top++] = t;
Queue[rear++]=t;
while(front!=rear)
{
int f,i;
start = Queue[front++];
p=g.adjlist[start].firstarc;
while(p!=NULL)
{
if(!vis[p->adjvex])
{
vis[p->adjvex]=1;
temp[top++] = p->adjvex;
Queue[rear++]=p->adjvex;
}
p=p->nextarc;
}
}
}
int main()
{
int n,t,k,m;
scanf("%d",&n);
while(n--)
{
top = 0;
Mgraph G;
scanf("%d%d%d",&k,&m,&t);
creategraph(G,k,m);
BFS(G,t);
for(int i=0;i<top;i++){
if(i<top-1){
printf("%d ",temp[i]);
}
else{
printf("%d\n",temp[i]);
}
}
}
return 0;
}
B - 数据结构实验之图论二:图的深度遍历
Description
请定一个无向图,顶点编号从0到n-1,用深度优先搜索(DFS),遍历并输出。遍历时,先遍历节点编号小的。
Input
输入第一行为整数n(0 < n < 100),表示数据的组数。 对于每组数据,第一行是两个整数k,m(0 < k < 100,0 < m < k*k),表示有m条边,k个顶点。 下面的m行,每行是空格隔开的两个整数u,v,表示一条连接u,v顶点的无向边。
Output
输出有n行,对应n组输出,每行为用空格隔开的k个整数,对应一组数据,表示DFS的遍历结果。
Sample
Input
1
4 4
0 1
0 2
0 3
2 3
Output
0 1 2 3
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int map[101][101];
int ans[101];
int temp[101];
int count = 0;
int k = 0;
void DFS(int n)
{
ans[n] = 1;
temp[count++] = n;
for(int i=0;i<k;i++){
if(!ans[i] && map[n][i]){
DFS(i);
}
}
}
int main()
{
int T,m,x,y;
scanf("%d",&T);
while(T--){
memset(map,0,sizeof(map));
memset(ans,0,sizeof(ans));
memset(temp,0,sizeof(temp));
count = 0;
scanf("%d%d",&k,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
map[x][y]=1;
map[y][x]=1;
}
DFS(0);
for(int i=0;i<count;i++){
if(i<count-1){
printf("%d ",temp[i]);
}
else{
printf("%d\n",temp[i]);
}
}
}
return 0;
}
数据结构实验之图论三:判断可达性
Description
在古老的魔兽传说中,有两个军团,一个叫天灾,一个叫近卫。在他们所在的地域,有n个隘口,编号为1..n,某些隘口之间是有通道连接的。其中近卫军团在1号隘口,天灾军团在n号隘口。某一天,天灾军团的领袖巫妖王决定派兵攻打近卫军团,天灾军团的部队如此庞大,甚至可以填江过河。但是巫妖王不想付出不必要的代价,他想知道在不修建任何通道的前提下,部队是否可以通过隘口及其相关通道到达近卫军团展开攻击。由于n的值比较大(n<=1000),于是巫妖王找到了擅长编程的你 =_=,请你帮他解决这个问题,否则就把你吃掉变成他的魔法。为了拯救自己,赶紧想办法吧。
Input
输入包含多组,每组格式如下。
第一行包含两个整数n,m(分别代表n个隘口,这些隘口之间有m个通道)。
下面m行每行包含两个整数a,b;表示从a出发有一条通道到达b隘口(注意:通道是单向的)。
Output
如果天灾军团可以不修建任何通道就到达1号隘口,那么输出YES,否则输出NO。
Sample
Input
2 1
1 2
2 1
2 1
Output
NO
YES
DFS做法
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int map[1001][1001];
int ans[1001];
int flag = 0;
int k = 0;
void DFS(int n)
{
ans[n] = 1;
if(n==1){
flag = 1;
}
for(int i=1;i<=k;i++){
if(!ans[i] && map[n][i]){
DFS(i);
}
}
}
int main()
{
int m,x,y;
while(scanf("%d%d",&k,&m)!=EOF){
memset(map,0,sizeof(map));
memset(ans,0,sizeof(ans));
flag = 0;
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
map[x][y]=1;
}
DFS(k);
if(flag){
printf("YES\n");
}
else{
printf("NO\n");
}
}
return 0;
}
BFS做法
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int map[1001][1001];
int ans[1001];
int flag=0;
int temp[1001];
int k = 0;
void BFS(int t)
{
int front,rear,start;
front=rear=0;
ans[t] = 1;
temp[rear++] = t;
while(rear>front){
start = temp[front++];
if(start==1){
flag = 1;
}
for(int i=1;i<=k;i++){
if(!ans[i] && map[start][i]){
ans[i] = 1;
temp[rear++]=i;
}
}
}
}
int main()
{
int m,x,y;
while(scanf("%d%d",&k,&m)!=EOF){
memset(map,0,sizeof(map));
memset(ans,0,sizeof(ans));
memset(temp,0,sizeof(temp));
flag = 0;
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
map[x][y]=1;
}
BFS(k);
if(flag){
printf("YES\n");
}
else{
printf("NO\n");
}
}
return 0;
}
D - 数据结构实验之图论四:迷宫探索
Description
有一个地下迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关;请问如何从某个起点开始在迷宫中点亮所有的灯并回到起点?
Input
连续T组数据输入,每组数据第一行给出三个正整数,分别表示地下迷宫的结点数N(1 < N <= 1000)、边数M(M <= 3000)和起始结点编号S,随后M行对应M条边,每行给出一对正整数,表示一条边相关联的两个顶点的编号。
Output
若可以点亮所有结点的灯,则输出从S开始并以S结束的序列,序列中相邻的顶点一定有边,否则只输出部分点亮的灯的结点序列,最后输出0,表示此迷宫不是连通图。
访问顶点时约定以编号小的结点优先的次序访问,点亮所有可以点亮的灯后,以原路返回的方式回到起点。
Sample
Input
1
6 8 1
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5
Output
1 2 3 4 5 6 5 4 3 2 1
Hint
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int map[1001][1001];
int vis[1001];
int ans[1001];
int k,m,threadmbcinfostruct;
int count;
void DFS(int n)
{
vis[n] = 1;
ans[count++] = n;
for(int i=1;i<=k;i++){
if(!vis[i] && map[n][i]){
DFS(i);
ans[count++] = n;
}
}
}
int main()
{
int T,x,y,t;
scanf("%d",&T);
while (T--)
{
memset(map,0,sizeof(map));
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
count = 0;
scanf("%d%d%d",&k,&m,&t);
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
map[x][y] = 1;
map[y][x] = 1;
}
DFS(t);
for(int i=0;i<count;i++){
printf("%d ",ans[i]);
}
if(count==2*k-1){
printf("\n");
}
else{
printf("0\n");
}
}
return 0;
}
数据结构实验之图论五:从起始点到目标点的最短步数(BFS)
Description
在古老的魔兽传说中,有两个军团,一个叫天灾,一个叫近卫。在他们所在的地域,有n个隘口,编号为1..n,某些隘口之间是有通道连接的。其中近卫军团在1号隘口,天灾军团在n号隘口。某一天,天灾军团的领袖巫妖王决定派兵攻打近卫军团,天灾军团的部队如此庞大,甚至可以填江过河。但是巫妖王不想付出不必要的代价,他想知道在不修建任何通道的前提下,部队是否可以通过隘口及其相关通道到达近卫军团展开攻击;如果可以的话,最少需要经过多少通道。由于n的值比较大(n<=1000),于是巫妖王找到了擅长编程的你 =_=,请你帮他解决这个问题,否则就把你吃掉变成他的魔法。为了拯救自己,赶紧想办法吧。
Input
输入包含多组,每组格式如下。
第一行包含两个整数n,m(分别代表n个隘口,这些隘口之间有m个通道)。
下面m行每行包含两个整数a,b;表示从a出发有一条通道到达b隘口(注意:通道是单向的)。
Output
如果天灾军团可以不修建任何通道就到达1号隘口,那么输出最少经过多少通道,否则输出NO。
Sample
Input
2 1
1 2
2 1
2 1
Output
NO
1
#include<stdio.h>
#include<string.h>
#define MAXSIZE 1001
int map[MAXSIZE][MAXSIZE];
int n,m;
void BFS(int n)
{
int vis[MAXSIZE],queue[MAXSIZE],step[MAXSIZE];
int rear,front,start;
int top = 0;
for(int i=0;i<n;i++){
vis[i] = 0;
}
rear = front = 0;
vis[n] = 1;
step[n] = 0;
queue[rear++] = n;
while(rear>front){
start = queue[front++];
for(int i=1;i<=n;i++){
if(!vis[i] && map[start][i]==1){
vis[i] = 1;
step[i] = step[start]+1;
queue[rear] = i;
if(queue[rear]==1){
printf("%d\n",step[1]);
return;
}
else{
rear++;
}
}
}
}
printf("NO\n");
}
int main()
{
int u,v;
while(scanf("%d%d",&n,&m)!=EOF){
memset(map,0,sizeof(map));
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
map[u][v] = 1;
}
BFS(n);
}
return 0;
}
数据结构实验之图论六:村村通公路
Description
当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。
Input
连续多组数据输入,每组数据包括村落数目N(N <= 1000)和可供选择的道路数目M(M <= 3000),随后M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个村庄的编号和修建该道路的预算成本,村庄从1~N编号。
Output
输出使每个村庄都有公路连通所需要的最低成本,如果输入数据不能使所有村庄畅通,则输出-1,表示有些村庄之间没有路连通。
Sample
Input
5 8
1 2 12
1 3 9
1 4 11
1 5 3
2 3 6
2 4 9
3 4 4
4 5 6
Output
19
Hint
prim算法
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXVEX 3001
#define INF 9999999
int map[MAXVEX][MAXVEX];
void prim(int n)
{
int mst[MAXVEX],lowcost[MAXVEX];
int pos,min,sum;
for(int i=2;i<=n;i++){
lowcost[i] = map[1][i];
mst[i] = 1;
}
sum = 0;
mst[1] = 0;
for(int i=2;i<=n;i++){
min = INF;
for(int j=2;j<=n;j++){
if(lowcost[j] && lowcost[j]<min){
min = lowcost[j];
pos = j;
}
}
if(min==INF){
printf("-1\n");
return;
}
else{
sum+=min;
}
lowcost[pos] = 0;
for(int j=2;j<=n;j++){
if(map[pos][j]<lowcost[j]){
lowcost[j] = map[pos][j];
mst[j] = pos;
}
}
}
printf("%d\n",sum);
}
int main()
{
int n,m,a,b,c;
while (scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
map[i][j] = INF;
}
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
map[a][b] = c;
map[b][a] = c;
}
prim(n);
}
return 0;
}
Kruskal算法
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXSIZE 3001
typedef struct node
{
int x;
int y;
int data;
}Node;
Node map[MAXSIZE];
int pre[MAXSIZE];
int vexs,edges;
void sort(Node map[])
{
for(int i=1;i<=edges-1;i++){
for(int j=1;j<=edges-i;j++){
if(map[j].data>map[j+1].data){
Node t;
t = map[j];
map[j] = map[j+1];
map[j+1] = t;
}
}
}
}
void init(int n)
{
for(int i=1;i<=n;i++){
pre[i] = i;
}
}
int findroot(int i)
{
if(pre[i] == i)
return pre[i];
else
{
pre[i] = findroot(pre[i]);
return pre[i];
}
}
int Union(int u, int v)
{
int t1 = findroot(u), t2 = findroot(v);
if(t1 != t2)
{
pre[t1] = pre[t2];
return 1;
}
else
return 0;
}
void Kruskal()
{
int sum,num,u,v,flag;
sum = num = flag = 0;
init(vexs);
sort(map);
for(int i=1;i<=edges;i++){
if(Union(map[i].x,map[i].y)){
sum+=map[i].data;
}
}
for(int i=1;i<=vexs;i++){
if(i==pre[i]){
flag++;
}
}
if(flag==1){
printf("%d\n",sum);
}
else{
printf("-1\n");
}
}
int main()
{
while (scanf("%d%d",&vexs,&edges)!=EOF)
{
for(int i=1;i<=edges;i++){
scanf("%d%d%d",&map[i].x,&map[i].y,&map[i].data);
}
Kruskal();
}
return 0;
}
J - 数据结构实验之图论十:判断给定图是否存在合法拓扑序列
Description
给定一个有向图,判断该有向图是否存在一个合法的拓扑序列。
Input
输入包含多组,每组格式如下。
第一行包含两个整数n,m,分别代表该有向图的顶点数和边数。(n<=10)
后面m行每行两个整数a b,表示从a到b有一条有向边。
Output
若给定有向图存在合法拓扑序列,则输出YES;否则输出NO。
Sample
Input
1 0 2 2 1 2 2 1
Output
YES NO
邻接矩阵简单做法
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXVEX 21
int map[MAXVEX][MAXVEX];
int in[MAXVEX];
void TopSort(int n)
{
int queue[MAXVEX];
int count,rear,front,top;
count = rear = front =0;
for(int i=1;i<=n;i++){
if(!in[i]){
queue[rear++] = i;
}
}
while(rear>front){
top = queue[front++];
count++;
for(int i=1;i<=n;i++){
if(map[top][i]){
in[i]--;
if(!in[i]){
queue[rear++]=i;
}
}
}
}
if(count==n){
printf("YES\n");
}
else{
printf("NO\n");
}
}
int main()
{
int u,v,n,m;
while(scanf("%d%d",&n,&m)!=EOF){
memset(map,0,sizeof(map));
memset(in,0,sizeof(in));
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
map[u][v] = 1;
map[u][v]=map[v][u] = 1;
in[v]++;
}
TopSort(n);
}
}
邻接表做法2,存在一些BUG,找半天没找出来,当MAXVEX为10时可以输出,变为其它数就不能输出了,非常诡异。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXVEX 10
typedef struct edgenode
{
int adjvex;
int weight;
edgenode *nextarc;
}ArcNode;
typedef struct vexnode
{
int data;
int count;
ArcNode *firstarc;
}VheadNode;
typedef struct graph
{
int vernums;
int edgenums;
VheadNode adjlist[MAXVEX];
}Mgraph;
void creategraph(Mgraph &G,int n1,int n2)
{
int u,v;
G.vernums = n1;
G.edgenums = n2;
for(int i=0;i<G.vernums;i++){
G.adjlist[i].data = i;
G.adjlist[i].firstarc=NULL;
}
ArcNode *s,*p;
for(int i=0;i<G.edgenums;i++){
scanf("%d%d",&u,&v);
s=(ArcNode*)malloc(sizeof(ArcNode));
s->adjvex=v;
p=G.adjlist[u].firstarc;
if(!p){
s->nextarc = NULL;
G.adjlist[u].firstarc = s;
}
else{
while(p->nextarc){
p=p->nextarc;
}
s->nextarc = p->nextarc;
p->nextarc = s;
}
}
}
void TopSort(Mgraph *g)
{
int top,u,v,num;
int stack[MAXVEX];
ArcNode *p;
p = NULL;
top = -1;
num = 0;
for(int i=0;i<g->vernums;i++){
g->adjlist[i].count = 0;
}
for(int i=0;i<g->vernums;i++){
p=g->adjlist[i].firstarc;
while(p!=NULL){
g->adjlist[p->adjvex].count++;
p=p->nextarc;
}
}
for(int i=0;i<g->vernums;i++){
if(g->adjlist[i].count==0){
stack[++top] = i;
}
}
while(top>-1){
u = stack[top--];
num++;
p = g->adjlist[u].firstarc;
while(p){
v = p->adjvex;
g->adjlist[v].count--;
if(g->adjlist[v].count==0){
stack[++top] = v;
num++;
}
p = p->nextarc;
}
}
if(num==g->vernums){
printf("YES\n");
}
else{
printf("NO\n");
}
}
int main()
{
int n,m;
Mgraph g;
while(scanf("%d%d",&n,&m)!=EOF){
creategraph(g,n,m);
TopSort(&g);
}
return 0;
}
M - 数据结构实验之图论十一:AOE网上的关键路径
Description
一个无环的有向图称为无环图(Directed Acyclic Graph),简称DAG图。
AOE(Activity On Edge)网:顾名思义,用边表示活动的网,当然它也是DAG。与AOV不同,活动都表示在了边上,如下图所示:
如上所示,共有11项活动(11条边),9个事件(9个顶点)。整个工程只有一个开始点和一个完成点。即只有一个入度为零的点(源点)和只有一个出度为零的点(汇点)。
关键路径:是从开始点到完成点的最长路径的长度。路径的长度是边上活动耗费的时间。如上图所示,1 到2 到 5到7到9是关键路径(关键路径不止一条,请输出字典序最小的),权值的和为18。
Input
这里有多组数据,保证不超过10组,保证只有一个源点和汇点。输入一个顶点数n(2<=n<=10000),边数m(1<=m <=50000),接下来m行,输入起点sv,终点ev,权值w(1<=sv,ev<=n,sv != ev,1<=w <=20)。数据保证图连通。
Output
关键路径的权值和,并且从源点输出关键路径上的路径(如果有多条,请输出字典序最小的)。
Sample
Input
9 11 1 2 6 1 3 4 1 4 5 2 5 1 3 5 1 4 6 2 5 7 9 5 8 7 6 8 4 8 9 4 7 9 2
Output
18 1 2 2 5 5 7 7 9
注意本题要求如果有多条路径,则输入字典序小的,所以不要忘记再更新路径,权值数组时不要忘记这个条件。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXVEX 50001
typedef struct vertex
{
int pre;
int rear;
int weight;
int out_degree;
int in_degree;
}Vertex;
Vertex vex[MAXVEX];
void initvex(int n)
{
for(int i=1;i<=n;i++){
vex[i].pre = 0;
vex[i].rear = 0;
vex[i].weight = 0;
vex[i].in_degree = 0;
vex[i].out_degree = 0;
}
}
void AOE(int n,int m,int pos)
{
int temp;
int path[MAXVEX],cost[MAXVEX];
memset(path,0,sizeof(path));
memset(cost,0,sizeof(cost));
for(int i=2;i<=n;i++){
temp = 0;
for(int j=1;j<=m;j++){
if(cost[vex[j].pre]<cost[vex[j].rear]+vex[j].weight ||
(cost[vex[j].pre]==cost[vex[j].rear]+vex[j].weight && vex[j].rear<path[vex[j].pre])){
cost[vex[j].pre] = cost[vex[j].rear] + vex[j].weight;
path[vex[j].pre] = vex[j].rear;
temp = 1;
}
}
if(!temp){
break;
}
}
printf("%d\n",cost[pos]);
while(path[pos]){
printf("%d %d\n",pos,path[pos]);
pos = path[pos];
}
}
int main()
{
int n,m,a,b,c,pos;
while (scanf("%d%d",&n,&m)!=EOF){
initvex(n);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
vex[i].pre = a;
vex[i].rear = b;
vex[i].weight = c;
vex[b].out_degree++;
vex[a].in_degree++;
}
for(int i=1;i<=n;i++){
if(vex[i].out_degree==0){
pos = i;
}
}
AOE(n,m,pos);
}
return 0;
}
N - 图结构练习——最短路径
Description
给定一个带权无向图,求节点1到节点n的最短路径。
Input
输入包含多组数据,格式如下。
第一行包括两个整数n m,代表节点个数和边的个数。(n<=100)
剩下m行每行3个正整数a b c,代表节点a和节点b之间有一条边,权值为c。
Output
每组输出占一行,仅输出从1到n的最短路径权值。(保证最短路径存在)
Sample
Input
3 2 1 2 1 1 3 1 1 0
Output
1 0
Hint
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define INF 999999
#define MAXVEX 101
int map[MAXVEX][MAXVEX];
void Dijkstra(int n)
{
int min,pos;
int vis[MAXVEX],dist[MAXVEX];
memset(vis,0,sizeof(vis));
memset(dist,0,sizeof(dist));
for(int i=1;i<=n;i++){
dist[i] = map[1][i];
}
vis[1] = 1;
for(int i=1;i<=n;i++){
min = INF;
for(int j=1;j<=n;j++){
if(!vis[j] && dist[j]<min){
min = dist[j];
pos = j;
}
}
vis[pos] = 1;
for(int j=1;j<=n;j++){
if(!vis[j] && map[pos][j]<INF && dist[j]>map[pos][j]+dist[pos]){
dist[j] = map[pos][j]+dist[pos];
}
}
}
printf("%d\n",dist[n]);
}
int main()
{
int n,m,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF){
memset(map,INF,sizeof(map));
for(int i=1;i<=n;i++){
map[i][i] = 0;
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
if(map[a][b]>c){
map[a][b] = c;
map[b][a] = c;
}
}
Dijkstra(n);
}
return 0;
}