某农业大学数据结构A-第13周作业

1.拓扑排序

【问题描述】

拓扑排序的流程如下:

1. 在有向图中选一个没有前驱的顶点并且输出之;

2. 从图中删除该顶点和所有以它为尾的弧。

重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。后一种情况则说明有向图中存在环。

采用邻接表存储有向图(可参考本次实验第2题代码),并通过栈来暂存所有入度为零的顶点。拓扑排序算法请参考教材上算法7.11和7.12或课件上的相应算法。

在本题中,读入一个有向图的信息(输入形式同本次实验第2题,详见下述【输入形式】),建立有向图并按照上述算法判断此图是否有回路,如果没有回路则输出拓扑有序的顶点数据序列。顶点的数据类型为int型。

注意:顶点编号从0开始。

【输入形式】仿照算法7.2的输入:

第1行输入图的结点个数n。第2行是图的各顶点数据。

之后的若干行(有向图为e行, 无向图为2e行) 依次输入各条边的弧尾、弧头的顶点编号。注意:因为算法7.2是按头插法建边链表的,所以要使得到的每个边链表中 都是按照邻接顶点的编号由小到大的顺序链接存储,就必须输入各边的顺序 首先是按照弧尾编号由小到大的顺序,并且输入弧尾相同的各边时 按照弧头顶点编号由大到小的顺序输入这些边,具体见样例输入。

最后一行输入-1和-1表示输入结束。

【输出形式】

如果读入的有向图含有回路,请输出“ERROR”,不包括引号。

如果读入的有向图不含有回路,请按照题目描述中的算法依次输出图的拓扑有序序列,每个整数后输出一个空格。

请注意行尾输出换行。

【样例输入】
4

0(空格)1(空格)2(空格)3

0(空格)1

1(空格)2

3(空格)2

-1(空格)-1

【样例输出】

3(空格)0(空格)1(空格)2(空格)

【说明】

本题中,需要严格的按照题目描述中的算法进行拓扑排序,并在排序的过程中将顶点数据先依次存储下来,直到最终能够判定有向图中不含回路之后,才能够进行输出,否则不能通过测试数据。

#include<iostream>
#include<stack>
using namespace std;

typedef struct arcnode
{
	int adjvex;
	struct arcnode*nextarc;
	int weight;
 } arcnode;
 
 typedef struct vertexnode
 {
 	int data;
 	arcnode*firstarc;
 }vertexnode;
 
 typedef struct 
 {
 	int vexnum,arcnum;
 	vertexnode v[100];
 }adjlist;
 
 void creat(adjlist &s)
 {
 	int x,y,k;
 	cin >> s.vexnum;
 	for(int i=0;i<s.vexnum;i++)
 	{
 		cin >> s.v[i].data;
 		//cout << s.a[i].weight;
 		s.v[i].firstarc=NULL;
	}
	for(k=0;k<50;k++)
	{
		cin >> x >> y;
		if(x==-1&&y==-1)
		break;
		else
		{
			arcnode*p1;
			p1=new arcnode;
			p1->adjvex=y;
			p1->nextarc=s.v[x].firstarc;
			s.v[x].firstarc=p1;
		 } 
	}
 }
 
 int indegree[100];
 int temp[100];
 
 void Findid(adjlist &g)//求入度 
 {
 	int i;
 	arcnode*p;
 	for(i=0;i<g.vexnum;i++)
 	indegree[i]=0;
 	for(i=0;i<g.vexnum;i++)
 	{
 		p=g.v[i].firstarc;
 		while(p!=NULL)
 		{
 			indegree[p->adjvex]++;
 			p=p->nextarc;
		 }
	 }
 }
 
 void toposort(adjlist &g)//拓扑排序 
 {
 	stack<int> s;
 	Findid(g);
 	arcnode*p;
 	for(int i=0;i<g.vexnum;i++)//将入度为1的放进栈 
 	{
 		if(indegree[i]==0)
 		s.push(i);
	 }
	 int count=0,i;
	 while(!s.empty())
	 {
	 	i=s.top();
	 	temp[count++]=s.top();//方便之后输出 
	 	s.pop();
	 	p=g.v[i].firstarc;
	 	while(p!=NULL)
	 	{
	 		int k=p->adjvex;
	 		indegree[k]--;
	 		if(indegree[k]==0)
	 		s.push(k);
	 		p=p->nextarc;
		 }
	 }
	 if(count<g.vexnum)
	 {
	 	cout << "ERROR";
	 }
	 else
	 {
	 	for (int i;i<count;i++)
	 	cout << temp[i] <<" ";
	 }
 }
 
 int main()
 {
 	adjlist s;
 	creat(s);
 	toposort(s);
 }
3.关键路径求解

【问题描述】AOE网示意图若在带权的有向图中,以顶点表示事件,以有向边表示活动,边上的权值表示活动的开销(如该活动持续的时间),则此带权的有向图称为AOE网。如果用AOE网来表示一项工程,那么,仅仅考虑各个子工程之间的优先关系还不够,更多的是关心整个工程完成的最短时间是多少;哪些活动的延期将会影响整个工程的进度,而加速这些活动是否会提高整个工程的效率。因此,通常在AOE网中 列出完成预定工程计划所需要进行的活动,每个活动计划完成的时间,要发生哪些事件以及这些事件与某活动之间的关系,从而可以确定该项工程是否可行,来估算工程完成的时间以及确定哪些活动是影响工程进度的关键。

   请参考《耿》教材的算法,编程求解上述问题。构建邻接表的函数,可以直接使用实验题“拓扑排序”中的代码。

【输入形式】第一行输入两个数字,依次是顶点数和边数;从第二行开始,输入边的信息,格式为(i  j  weight),i为弧尾顶点编号,j为弧头顶点编号,两个数据间用空格分隔;规定顶点编号从0开始。

【输出形式】关键活动的情况,格式为(顶点1  顶点2),两者间用1个空格分隔。要求:输出表示关键活动的各条弧时,按照弧尾顶点编号从小到大的顺序依次输出各条弧。
【样例输入】

6 8

0 2 2

0 1 3

1 4 3

1 3 2

2 5 3

2 3 4

3 5 2

4 5 1
【样例输出】

0 2

2 3

3 5

【样例说明】输入的(i  j  weight)时,不用输入括号。输出(顶点1  顶点2)时,不用输出括号。


#include<iostream>
#include<stack>
using namespace std;

typedef struct arcnode
{
	int adjvex;
	struct arcnode*nextarc;
	int weight;
 } arcnode;
 
 typedef struct vertexnode
 {
 	int data;
 	arcnode*firstarc;
 }vertexnode;
 
 typedef struct 
 {
 	int vexnum,arcnum;
 	vertexnode v[100];
 }adjlist;
 
 void creat(adjlist &s)
 {
 	int x,y,k;
 	int w;
 	cin >> s.vexnum >>s.arcnum;
 	for(int i=0;i<s.vexnum;i++)
 	{
 		//cin >> s.v[i].data;
 		//cout << s.a[i].weight;
 		s.v[i].firstarc=NULL;
	}
	for(k=0;k<s.arcnum;k++)
	{
		cin >> x >> y >>w;
		
			arcnode*p1;
			p1=new arcnode;
			p1->adjvex=y;
			p1->weight=w;
			p1->nextarc=s.v[x].firstarc;
			s.v[x].firstarc=p1;
		 
	}
 }
 
 int indegree[100];
 int temp[100];
 int count;
int vl[200],ve[200];
 
 void Findid(adjlist &g)
 {
 	int i;
 	arcnode*p;
 	for(i=0;i<g.vexnum;i++)
 	indegree[i]=0;
 	for(i=0;i<g.vexnum;i++)
 	{
 		p=g.v[i].firstarc;
 		while(p!=NULL)
 		{
 			indegree[p->adjvex]++;
 			p=p->nextarc;
		 }
	 }
 }
 
 void toposort(adjlist &g)//拓扑排序 
 {
 	stack<int> s;
 	Findid(g);
 	arcnode*p;
 	for(int i=0;i<g.vexnum;i++)
 	{
 		if(indegree[i]==0)
 		s.push(i);
	 }
	 count=0;
	 int i;
	 while(!s.empty())
	 {
	 	i=s.top();
	 	temp[count++]=s.top();
	 	s.pop();
	 	p=g.v[i].firstarc;
	 	while(p!=NULL)
	 	{
	 		int k=p->adjvex;
	 		indegree[k]--;
	 		if(indegree[k]==0)
	 		s.push(k);
	 		if(ve[i]+p->weight>ve[k])
	 		    ve[k]=ve[i]+p->weight;
	 		p=p->nextarc;
		 }
	 }
	/* if(count<g.vexnum)
	 {
	 	cout << "ERROR";
	 }
	 else
	 {
	 	for (int i;i<count;i++)
	 	cout << temp[i] <<" ";
	 }*/
 }
 
void getpath(adjlist &g)
{
	int top=count-1;
	int in,out,i;
	in=temp[top--];
	for(i=0;i<g.vexnum;i++)
	{
		vl[i]=ve[in];
	}
	while(top!=-1)
	{
		in = temp[top--];
		arcnode *p1=g.v[in].firstarc;
		while(p1)
		{
			out=p1->adjvex;
			if(vl[in]>vl[out]-p1->weight)
			{
				vl[in]=vl[out]-p1->weight;
			}
			p1=p1->nextarc;
		}
	}
	for(in=0;in<g.vexnum;in++)
	{
		arcnode *p2=g.v[in].firstarc;
		while(p2)
		{
			out=p2->adjvex;
			int ee=ve[in];
			int el=vl[out]-p2->weight;
			if(ee==el)
			cout << in <<" "<<out<<endl;
			p2=p2->nextarc;
		}
	}
}

 
 int main()
 {
 	adjlist s;
 	creat(s);
 	toposort(s);
 	getpath(s);
 	return 0;
 }
4.迪杰斯特拉算法求最短路径

【问题描述】

在带权有向图G中,给定一个源点v,求从v到G中的其余各顶点的最短路径问题,叫做单源点的最短路径问题。

在常用的单源点最短路径算法中,迪杰斯特拉算法是最为常用的一种,是一种按照路径长度递增的次序产生最短路径的算法。

请在本题中,读入一个有向图的带权邻接矩阵(即数组表示),建立有向图并参考《耿》教材中算法7.15,编程求出源点至图中每一个其它顶点的最短路径长度。

【输入形式】

输入的第一行依次是2个正整数n和s,表示图中共有n个顶点,且源点编号为s(顶点编号从0~n-1)。其中n不超过50,s小于n。

以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,对应的整数也是0。

【输出形式】

只有一行,共有n-1个整数,表示源点至其它每个顶点 (编号从小到大顺序) 各自的最短路径长度。如果不存在从源点至相应顶点的路径,则输出-1。

注意: 各输出数据间用1个空格分隔, 行尾输出换行。

【样例输入】

4  1
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0

【样例输出】

6 4 7

【样例说明】

在本题中,需要在计算最短路径的过程中将每个顶点是否可达记录下来(可用非常大的整数来标记不可达),直到求出每个可达顶点的最短路径之后,算法才能够结束。 

迪杰斯特拉算法的特点是按照路径长度递增的顺序,依次添加下一条长度最短的边,从而不断构造出相应顶点的最短路径。 

#include<iostream>
using namespace std;
#define WU 100000

typedef struct graph
{
	int arc[100][100];
	int weight;
	int arcnum,vexnum;
}graph;

void creat(graph &g)
{
	int i,j;
	int temp;
	for(i=0;i<g.vexnum;i++)
	{
		for(j=0;j<g.vexnum;j++)
		{
			cin >> temp;
			if(temp!=0)
			g.arc[i][j]=temp;
			else
			g.arc[i][j]=WU;
		}
	}
}

int dis[100];
int path[100];
int visited[100];
//数组path[n]是一个字符串。
//表示当前所找到的从始点v到终点vi的最短路径。
//若从v到vi有弧,则path[i]为vvi,否则为空串。 

//数组dis[n]表示从当前所找到的从始点v到终点vi
//的最短路径的长度。 

//visited[n]表示是否有过判断。 

void dijkstra(graph &g)
{
	int n=g.vexnum;
	int v0=g.arcnum;
	int i,j,k;
	for(i=0;i<n;i++)//初始化 
	{
		if(g.arc[v0][i]>0 && i!=v0)
		{
			dis[i]=g.arc[v0][i];
		    path[i]=v0;
		}
		else
		{
			dis[i]=WU;
			path[i]=-1;
		}
		visited[i]=0;
	}
	path[v0]=v0;
	dis[v0]=0;
	visited[v0]=1;
	for(i=1;i<n;i++)
	{
		int min=WU;
		int u;
		for(j=0;j<n;j++)
		{
			if(visited[j]==0 && dis[j]<min)
			{
				min = dis[j];
				u=j;
			}
		}
		visited[u]=1;
		for(k=0;k<n;k++)
		{
			if(visited[k]==0 && g.arc[u][k]<WU && min+g.arc[u][k]<dis[k])
			{
				dis[k]=min+g.arc[u][k];
				path[k]=u; 
			}
		}
	}
}

void print(graph g)
{
	int i;
	for(i=0;i<g.vexnum;i++)
	{
		if(dis[i])
		{
			if(dis[i]<WU)
			{
				cout << dis[i] <<" ";
			}
			else
			{
				cout << -1 <<" ";
			}
	    }
	}

}

int main()
{
	graph g;
	cin >> g.vexnum >> g.arcnum;
	creat(g);
	dijkstra(g);
	print(g);
	return 0;
}
5.弗洛伊德算法求最短路径

【问题描述】

对于下面一张若干个城市,以及城市之间距离的地图,请采用弗洛伊德算法求出所有城市之间的最短路径。

【输入形式】

顶点个数n,以及n*n的邻接矩阵,其中不可达使用9999表示。

【输出形式】

每两个顶点之间的最短路径和经过的顶点

注意:规定顶点自身到自身的dist值为0,此时path为该顶点编号。

【样例输入】

4

9999 4 11 9999

6 9999 2 9999

1 9999 9999 1

9999 3 9999 9999

【样例输出】

from(空格)0(空格)to(空格)0:(空格)dist(空格)=(空格)0(空格)path:0(换行)

from 0 to 1: dist = 4 path:0 1
from 0 to 2: dist = 6 path:0 1 2
from 0 to 3: dist = 7 path:0 1 2 3
from 1 to 0: dist = 3 path:1 2 0
from 1 to 1: dist = 0 path:1
from 1 to 2: dist = 2 path:1 2
from 1 to 3: dist = 3 path:1 2 3
from 2 to 0: dist = 1 path:2 0
from 2 to 1: dist = 4 path:2 3 1
from 2 to 2: dist = 0 path:2
from 2 to 3: dist = 1 path:2 3
from 3 to 0: dist = 6 path:3 1 2 0
from 3 to 1: dist = 3 path:3 1
from 3 to 2: dist = 5 path:3 1 2
from 3 to 3: dist = 0 path:3

#include<iostream>
#include<vector>
#define max 100
#define WU 9999 
using namespace std;

int n;
int dist[max][max];
vector<int> path[max][max];

vector<int> Joinlist(int i,int k,int j)//合并路径
{
	path[i][j].clear();
	int temp = path[i][k].back();
	path[i][k].pop_back();
	vector<int> s;
	int m,n;
	for (m = 0; m < path[i][k].size(); m++)
	{
		s.push_back(path[i][k][m]);
	}
	for (n = 0; n < path[k][j].size(); n++)
	{
		s.push_back(path[k][j][n]);
	}
	path[i][k].push_back(temp);
	return s;
}

void floyd()
{
	for (int i = 0; i < n; i++)//初始化dist[i][j]与path[i][j]
	{
		for (int j = 0; j < n; j++)
		{
			cin >> dist[i][j];
			if (dist[i][j] < WU)
			{
				path[i][j].push_back(i);
				path[i][j].push_back(j);
			}
			else if(i==j&&dist[i][j]==WU)
			{
				path[i][j].push_back(i);
			}
		}
	}
	
	for (int k = 0; k < n; k++)
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				if (dist[i][k] + dist[k][j] < dist[i][j]&&i!=j)
				{
					dist[i][j] = dist[i][k] + dist[k][j];
					path[i][j] = Joinlist(i,k,j);
				}
			}
		}
	}
}

void print()
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (dist[i][j] == WU) dist[i][j] = 0;
			cout << "from " <<i << " to " <<j <<":" 
			    <<" dist = " << dist[i][j] << " path:";
			for (int k = 0; k < path[i][j].size();k++)
			{
				cout << path[i][j][k] <<" ";
			}
			cout << endl;
		}
	}
}

int main()
{
	cin >> n;
	floyd();
	print();
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值