2020寒假【gmoj1504】【城市连接】【dijkstra最短路】

43 篇文章 0 订阅
27 篇文章 0 订阅

题目描述

天网恢恢,疏而不漏,经过上一次的抓捕,OI总部终于获取了怪盗的特征!现在,我们需要在基德再次来之前就把他的特征送到超级大牛的手上,可惜超级大牛不在总部,所以飞过海必须尽快把资料送到大牛家里。已知OI总部到大牛家中间有n-2个城城市,为了尽快达到目的地,飞过海通过水晶球了解到OI总部到大牛家的路线图,图上显示了n个城之间的连接距离。

可是飞过海很忙,需要请你来帮忙编写一个程序。

输入

输入文件中的第一行为一个整数n(n<=1000)。

第二行至第n+1行,每行有n个数。其中:第i+1行中表示第i个城市与其他城市之间的连接关系,0表示不连接,其它数字表示连接的距离。

输出

输出文件中的第一行为n个整数,表示所选的线路。

第二行中为一个数,表示最短距离。

样例输入

7
0 3 5 0 0 0 0
0 0 0 7 8 6 0
0 0 0 0 4 5 0
0 0 0 0 0 0 4
0 0 0 0 0 0 7
0 0 0 0 0 0 6
0 0 0 0 0 0 0

样例输出

1 2 4 7
14

分析

这题先看数据。可以用邻接矩阵。但是floyed会超时,只能选用dijkatra,时间复杂度O(n2)。

其实这题就跟dijkstra的模板题差不多,模板熟打出来就行。但是怎样输出过程呢?
先建一个p数组,初始化为-1,每当蓝点变成白点的时候记录当前的点(因为白点一定是当前松弛的最短路)。最后while循环走一遍这条路,因为是反着的,所以再开个数组记录,顺序输出。
当然,递归也不是不可以。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,k,q,z;
int a[1001][1001],d[1001],p[1001],minn,pp[1001];
bool b[1001];//蓝白点 
void input()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
			if(a[i][j]==0) a[i][j]=0x3fffff;
		} 
	}
}
void dijkstra()
{
	for(int i=1;i<=n;i++)
	{
		minn=0x3fffff;
		k=0;
		for(int j=1;j<=n;j++)
		{
			if((!b[j])&&(d[j]<minn))
			{
				minn=d[j];
				k=j;
			}
		}
		if(k==0) break;
		b[k]=true;
		for(int j=1;j<=n;j++)
	    {
	    	if(d[k]+a[k][j]<d[j]&&(!b[j]))
	    	{
	    		d[j]=d[k]+a[k][j];//变点
	    		p[j]=k;//记录
	    	}
	    }
	}
} 
int main()
{
	freopen("city.in","r",stdin);
	freopen("city.out","w",stdout); 
	input();
	memset(p,-1,sizeof(p));
	for(int i=1;i<=n;i++)
	{
		d[i]=a[1][i];
	} 
    memset(b,false,sizeof(b));
    b[1]=true;
    d[1]=0;//最短路第一个设为0;
	dijkstra(); //最短路算法;
	cout<<1<<' ';
	int nn=n,s=0;
	while(p[nn]!=-1)//输出部分
	{
		s++;
	    pp[s]=p[nn];
		nn=p[nn];
	}
	for(int i=s;i>=1;i--)
	{
		cout<<pp[i]<<' ';
	}
	cout<<n<<endl;
	cout<<d[n];
	fclose(stdin);
	fclose(stdout);
	return 0;
} 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值