河南理工大学算法协会暑期集训积分赛(四)
B. wzy的大冒险——出发咯QAQ
单点时限: 2.0 sec
内存限制: 512 MB
wzy踏上了冒险的旅程。
现在他从地精手里买了一份地图,地图上有n个城镇。
他从第一个城镇出发,走向(没钱只能走)第n个城镇,现在,请你帮wzy找到一条最短的路径,并倒序(从n到1)输出一条最短路径。
举个栗子:如果有两条路径6 4 3 1和6 5 2 1,我们选择6 4 3 1这条。
地精小提示:路是单向的QAQ。
输入格式
第一行两个数n,m ,(1≤n≤103,1≤m≤103)
接下来m行,每行三个数x,y,z,表示点 x 与点 y 之间有一条权值为 z 的有向边 (1≤x,y,z≤103).
输出格式
第一行一个整数表示 1 到 n 的最短距离;
第二行倒序输出这条路径。
样例
input
5 7
1 2 69
1 3 87
1 4 79
2 5 94
2 3 10
3 5 79
4 5 43
output
122
5 4 1
分析:
要求最短路径很简单,直接套用模板就可以;关键是输出路径;竞赛的时候,脑子短路了,陷入思维定式,然后卡了两个多小时不知道怎么输出路径,终于在结束前6秒AC了,真的是懵逼的…压哨…
先贴一下我的代码;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e3+7;
const int mod=1e9+7;
#define INF 0x3f3f3f3f
//vector<pair<int,int> > G[maxx];
int dis[maxx];
int c[maxx][maxx];
int cc[maxx][maxx];
int s[maxx];
int v,n,m;
void dijkstra()
{
for(int i=1;i<=n;i++) dis[i]=c[v][i];
dis[v]=0;
s[v]=1;
for(int i=2;i<=n;i++)
{
int temp=INF;
int u=v;
for(int j=1;j<=n;j++)
{
if(!s[j]&&dis[j]<temp)
{
u=j;
temp=dis[j];
}
}
s[u]=1;
for(int j=1;j<=n;j++)
{
if(!s[j]&&c[u][j]<INF)
{
int newdis=dis[u]+c[u][j];
if(newdis<dis[j])
{
dis[j]=newdis;
}
}
}
}
}
int main()
{
cin >>n>>m;
int x,y,z;
memset(dis,INF,sizeof dis);
memset(s,0,sizeof 0);
memset(c,INF,sizeof c);
memset(cc,INF,sizeof cc);
for(int i=0;i<m;i++)
{
cin >>x>>y>>z;
c[x][y]=z;
cc[y][x]=z;//这个数组保证输出路径的时候不会往回走
}
v=1;
dijkstra();
cout <<dis[n]<<endl;
int u;
int e=n;
cout <<e;//先输出最后一个点
while(1)//现在开始输出路径;倒着输出;
{
for(u=1;u<=n;u++)//从所有的点中找到与上个点相连的点
{
if(dis[e]-dis[u]==cc[e][u]&&cc[e][u]!=INF)//如果这个点上个点相连,并且在最短路径上面那么输出这个点,并且在从这个点寻找路径上的下一个点
{
e=u;
cout <<" "<<e;
break;
}
}
if(e==1)
break;
}
cout <<endl;
return 0;
}
这是我做题时想到的一个思路;后来在网上借鉴了许多大佬的通用方法;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e3+10;
const int mod=1e9+7;
#define INF 0x3f3f3f3f
int dis[maxx];
int c[maxx][maxx];
int s[maxx];
int pt[maxx];
int v,n,m;
void dijkstra()
{
for(int i=2;i<=n;i++) dis[i]=c[v][i];//经过此k点到达j点的路径是否小于其他到达j点的路径
dis[v]=0;
s[v]=1;
for(int i=2;i<=n;i++)//共循环n-1次,每循环一次,确定一条最短路,再次循环时这条路就不用考虑了,去寻找下一条最短路
{
int temp=INF;
int u=v;
for(int j=1;j<=n;j++)//在源点找到一个离他最近的点(并且没有被标记过),并且标记该点,然后使用
{
if(!s[j]&&dis[j]<temp)
{
u=j;
temp=dis[j];
}
}
s[u]=1;
for(int j=1;j<=n;j++)
{
if(!s[j]&&c[u][j]<INF)
{
int newdis=dis[u]+c[u][j];
if(newdis<dis[j])//经过此k点到达j点的路径是否小于其他到达j点的路径
{
dis[j]=newdis;
pt[j]=u;//表示最短路径j点是由u点传过来的
}
}
}
}
}
int main()
{
cin >>n>>m;
int x,y,z;
memset(dis,INF,sizeof dis);
memset(s,0,sizeof 0);
memset(c,INF,sizeof c);
for(int i=0;i<m;i++)
{
cin >>x>>y>>z;
c[x][y]=z;//此处一定要存储成有向图,否则有些路径会发生错误;
}
for(int i=2;i<=n;i++)
{
if(c[1][i]!=INF)//把所有直接与1相连的点,上级都标记为1
pt[i]=1;
}
v=1;
dijkstra();
cout <<dis[n]<<endl;
int u=n;
cout<<u;
while(u!=1)
{
u=pt[u];
cout <<" "<<u;
}
cout <<'\n';
return 0;
}