1987 Problem D 最短路径

问题 D: 最短路径

时间限制: 1 Sec  内存限制: 32 MB
提交: 187  解决: 34
 

题目描述

有n个城市m条道路(n<1000, m<10000),每条道路有个长度,请找到从起点s到终点t的最短距离和经过的城市名。

输入

输入包含多组测试数据。

每组第一行输入四个数,分别为n,m,s,t。

接下来m行,每行三个数,分别为两个城市名和距离。

输出

每组输出占两行。

第一行输出起点到终点的最短距离。

第二行输出最短路径上经过的城市名,如果有多条最短路径,输出字典序最小的那条。若不存在从起点到终点的路径,则输出“can't arrive”。

样例输入

3 3 1 3
1 3 3
1 2 1
2 3 1

样例输出

2
1 2 3

经验总结

我只想说。。。。这题真是出了鬼了,同样的思想,邻接表可以通过,邻接矩阵却怎么都无法通过,说起来邻接表确实和邻接矩阵不同,邻接表中的存放的都是可达边,而邻接矩阵是用最大整数来近似代表两点之间不可达,这里可能就会出一些问题。。。
但是,,,我确实木有试出来到底怎样邻接矩阵才可以通过测试(表示很无奈- -||),评论区已有大佬试了出来。。就是输入数据的两个顶点之间竟然有多条边,详情请见评论区大佬的代码_(:з」∠)_
用邻接表实现就是中规中矩的迪杰斯特拉就可以了,关于题中所说有多条最短路径时输出字典序最小的那一条,先用容器数组存储多条路经,然后再利用DFS进行比较~~感谢评论区的童鞋指正,原来的比较顺序错了,现在已经更正过来了~~

正确代码

#include <cstdio>
#include <vector>
#include <set>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
bool vis[maxn];
int n,d[maxn],G[maxn][maxn];
vector<int> pre[maxn],temppath,path;
struct node
{
	int v,w;
	node(int x,int y):v(x),w(y){ };
};
vector<node> adj[maxn];
void Dijkstra(int s)
{
	fill(d,d+maxn,INF);
	fill(vis,vis+maxn,false);
	d[s]=0;
	for(int i=1;i<=n;++i)
	{
		int min=INF,u=-1;
		for(int j=1;j<=n;++j)
		{
			if(d[j]<min&&vis[j]==false)
			{
				u=j;
				min=d[j];
			}
		}
		if(u==-1)
			return ;
		vis[u]=true;
		for(int j=0;j<adj[u].size();++j)
		{
			int v=adj[u][j].v;
			if(vis[v]==false)
			{
				if(d[u]+adj[u][j].w<d[v])
				{
					d[v]=d[u]+adj[u][j].w;
					pre[v].clear();
					pre[v].push_back(u);
				}
				else if(d[u]+adj[u][j].w==d[v])
				{
					pre[v].push_back(u);
				}
			}
		}
	}
}
bool compare(vector<int> a,vector<int> b)
{
	int i=a.size()-1,j=b.size()-1;
	while(i>=0&&j>=0)
	{
		if(a[i]!=b[j])
			return a[i]<b[j];
		--i;--j;
	}
	return a.size()<b.size();
}
 
void DFS(int v,int s)
{
	if(v==s)
	{
		temppath.push_back(v);
		if(path.size()==0)
			path=temppath;
		else if(compare(temppath,path))
			path=temppath;
		temppath.pop_back();
		return ;
	}
	temppath.push_back(v);
	for(int i=0;i<pre[v].size();++i)
		DFS(pre[v][i],s);
	temppath.pop_back();
}
int main()
{
	int m,s,t,d1,d2,w;
    while(~scanf("%d %d %d %d",&n,&m,&s,&t))
    {
		for (int i=1;i<=n;++i)
            adj[i].clear();
        for(int i=0;i<m;++i)
        {
        	scanf("%d %d %d",&d1,&d2,&w);
        	adj[d1].push_back(node(d2,w));
        	adj[d2].push_back(node(d1,w));
		}
		Dijkstra(s);
		if(d[t]==INF)
		{
			printf("can't arrive\n");
		}
		else
		{
			printf("%d\n",d[t]);
			temppath.clear();
			path.clear();
			DFS(t,s);
			for(int i=path.size()-1;i>=0;--i)
				printf("%d%c",path[i],i>0?' ':'\n');
		}
    }
    return 0;
}

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值