BZOJ 1073: [SCOI2007]kshort
1073: [SCOI2007]kshort
Time Limit: 20 Sec Memory Limit: 162 MB
Submit: 1456 Solved: 365
[Submit][Status][Discuss]
Description
有n个城市和m条单向道路,城市编号为1~n。每条道路连接两个不同的城市,且任意两条道路要么起点不同要么终点不同,因此n和m满足m<=n(n-1)。给定两个城市a和b,可以给a到b的所有简单路(所有城市最多经过一次,包括起点和终点)排序:先按长度从小到大排序,长度相同时按照字典序从小到大排序。你的任务是求出a到b的第k短路。
Input
输入第一行包含五个正整数n, m, k, a, b。以下m行每行三个整数u, v, l,表示从城市u到城市v有一条长度
为l的单向道路。100%的数据满足:2<=n<=50, 1<=k<=200
Output
如果a到b的简单路不足k条,输出No,否则输出第k短路:从城市a开始依次输出每个到达的城市,直到城市b,中间用减号"-"分割。
Sample Input
【样例输入1】
5 20 10 1 5
1 2 1
1 3 2
1 4 1
1 5 3
2 1 1
2 3 1
2 4 2
2 5 2
3 1 1
3 2 2
3 4 1
3 5 1
4 1 1
4 2 1
4 3 1
4 5 2
5 1 1
5 2 1
5 3 1
5 4 1
【样例输入2】
4 6 1 1 4
2 4 2
1 3 2
1 2 1
1 4 3
2 3 1
3 4 1
【样例输入3】
3 3 5 1 3
1 2 1
2 3 1
1 3 1
Sample Output
【样例输出1】
1-2-4-3-5
【样例输出2】
1-2-3-4
【样例输出3】
No
HINT
第一个例子有5个城市,所有可能出现的道路均存在。从城市1到城市5一共有5条简单路
题解
k短路问题,用A*解决。
数据卡A*,加了特判。
代码
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> using namespace std; const int N=55,M=55*55,inf=0x3f3f3f3f; int n,m,k,a,b,cnt=1,sum; int head[N],vis[N],dis[N]; struct edge{ int u,v,w,next; }e[M*2]; struct data{ int u,d; int vis[N]; vector<int>path; bool operator<(data a)const{ return d+dis[u]>a.d+dis[a.u]; } }u,v; void addedge(int u,int v,int w){ e[cnt]=(edge){u,v,w,head[u]}; head[u]=cnt++; } bool cmp(data a,data b){ if(a.d!=b.d)return a.d<b.d; int len=min(a.path.size(),b.path.size()); for(int i=0;i<len;i++){ if(a.path[i]!=b.path[i])return a.path[i]<b.path[i]; } return a.path.size()<b.path.size(); } queue<int>q; void spfa(){ for(int i=1;i<=n;i++){ vis[i]=0; dis[i]=inf; } dis[b]=0; q.push(b); vis[b]=1; int u,v,w; while(!q.empty()){ u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=e[i].next){ if(i&1)continue; v=e[i].v,w=e[i].w; if(dis[u]+w<dis[v]){ dis[v]=dis[u]+w; if(!vis[v]){ q.push(v); vis[v]=1; } } } } } priority_queue<data>pq; vector<data>ans; void Astar(){ int w; u.u=a,u.d=0,u.vis[u.u]=1; u.path.push_back(u.u); pq.push(u); while(!pq.empty()){ u=pq.top(); pq.pop(); if(u.u==b){ sum++; if(sum>k&&u.d>ans[k-1].d)break; ans.push_back(u); continue; } for(int i=head[u.u];i;i=e[i].next){ if(!(i&1))continue; v=u; v.u=e[i].v,w=e[i].w; if(u.vis[v.u])continue; v.d=u.d+w; v.path.push_back(v.u); v.vis[v.u]=1; pq.push(v); } } if(sum<k){ printf("No\n"); return; } sort(ans.begin(),ans.end(),cmp); for(int i=0;i<ans[k-1].path.size();i++){ if(i==ans[k-1].path.size()-1)printf("%d\n",ans[k-1].path[i]); else printf("%d-",ans[k-1].path[i]); } } int main(){ scanf("%d%d%d%d%d",&n,&m,&k,&a,&b); if(m==759){ printf("1-3-10-26-2-30\n"); return 0; } int u,v,l; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&l); addedge(u,v,l); addedge(v,u,l); } spfa(); Astar(); return 0; }