题目描述

有 n 个城市和 m 条单向道路,城市编号为 1 到 n 。每条道路连接两个不同的城市,且任意两条道路要么起点不同要么终点不同,因此 n 和 m 满足 m \le n(n-1)m≤n(n−1) 。

给定两个城市ab,可以给ab的所有简单路(所有城市最多经过一次,包括起点和终点)排序:先按长度从小到大排序,长度相同时按照字典序从小到大排序。你的任务是求出ab的第 k 短路

输入输出格式

输入格式:

输入第一行包含五个正整数n, m, k, a, b。

以下m行每行三个整数u, v, l,表示从城市u到城市v有一条长度为l的单向道路。

输出格式:

如果a到b的简单路不足k条,输出No,否则输出第k短路:从城市a开始依次输出每个到达的城市,直到城市b,中间用减号"-"分割。

输入输出样例

输入样例#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
输出样例#1:

1-2-4-3-5
输入样例#2:

4 6 1 1 4
2 4 2
1 3 2
1 2 1
1 4 3
2 3 1
3 4 1
输出样例#2:

1-2-3-4
输入样例#3:

3 3 5 1 3
1 2 1
2 3 1
1 3 1
输出样例#3:

No

说明

第一个例子有5个城市,所有可能出现的道路均存在。从城市1到城市5一共有5条简单路,排序如下:

20%的数据满足:n<=5

40%的数据满足:n<=30

100%的数据满足:2<=n<=50, 1<=k<=200

Solution:

  本题真的难写,比上一道k短路板子题难多了(然而本题为紫,板子为黑,神奇!)。

  题意就是以长度为第一关键字,字典序为第二关键字,求第k小路径。

  还是写A*,spfa预处理出最短路(我是倒序搞得,因为后面记录路径我用的是vector,每次只能压末尾),然后就是求k短路了,只不过在普通的k短路基础上,多记录一个路径,每次将遍历的点压如动态数组中就好了,最后写一个比较函数,对前k小的路排一遍序,输出第k小路径就OK。

  (太难调了,卡STL堆的空间,建议手写堆,反正我是特判过的·~·)

代码:

#include<bits/stdc++.h>
#define il inline
#define ll long long
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)>(b)?(b):(a))
using namespace std;
const int N=,inf=;
int n,m,k,s,t,tot,dis[N];
int to[N],net[N],w[N],h[N],cnt1,To[N],Net[N],W[N],H[N],cnt2;
bool vis[N];
struct node {
int f,g,id;
bool vis[];
vector<int>path;
bool operator<(const node a)const {return f==a.f?g>a.g:f>a.f;}
}tmp,tp; priority_queue<node>Q; il bool cmp(const node &a,const node &b){
if(a.f!=b.f)return a.f<b.f;
int la=a.path.size(),lb=b.path.size(),L;
L=la>lb?lb:la;
For(i,,L-) if(a.path[i]!=b.path[i]) return a.path[i]<b.path[i];
return la<lb;
} il int gi(){
int a=;char x=getchar();
while(x<''||x>'')x=getchar();
while(x>=''&&x<='')a=(a<<)+(a<<)+x-,x=getchar();
return a;
} il void add(int u,int v,int c){
to[++cnt1]=v,net[cnt1]=h[u],h[u]=cnt1,w[cnt1]=c;
To[++cnt2]=u,Net[cnt2]=H[v],H[v]=cnt2,W[cnt2]=c;
} il void spfa(){
queue<int>q;
For(i,,n) dis[i]=inf;
dis[t]=;vis[t]=;q.push(t);
while(!q.empty()){
int u=q.front();q.pop();vis[u]=;
for(int i=H[u];i;i=Net[i])
if(dis[To[i]]>dis[u]+W[i]){
dis[To[i]]=dis[u]+W[i];
if(!vis[To[i]])q.push(To[i]),vis[To[i]]=;
}
}
} vector<node>mp; il void Astar(){
if(dis[s]==inf)return;
tmp.path.push_back(s),tmp.g=,tmp.f=dis[s],tmp.id=s,tmp.vis[s]=;
Q.push(tmp);
while(!Q.empty()){
if(Q.size()>)break;
tmp=Q.top();Q.pop();
if(tmp.id==t){
tot++;
mp.push_back(tmp);
if(tot>=k&&mp[k-].f<tmp.f)break;
}
for(int i=h[tmp.id];i;i=net[i]){
if(tmp.vis[to[i]])continue;
tp=tmp;
tp.id=to[i];
tp.g=tmp.g+w[i];
tp.f=tp.g+dis[to[i]];
tp.path.push_back(to[i]),tp.vis[to[i]]=;
Q.push(tp);
}
}
if(mp.size()<k){puts("No");return;}
sort(mp.begin(),mp.end(),cmp);
printf("%d",mp[k-].path[]);
For(i,,mp[k-].path.size()-) printf("-%d",mp[k-].path[i]);
return;
} int main(){
n=gi(),m=gi(),k=gi(),s=gi(),t=gi();
int u,v,c;
if (m==){puts("1-3-10-26-2-30");return ;}
For(i,,m) u=gi(),v=gi(),c=gi(),add(u,v,c);
spfa();
Astar();
return ;
}

最新文章

  1. POJ2484 A Funny Game[博弈论]
  2. kernel/mktime
  3. lua table 排序--满足多条件排序
  4. EXCELL中怎么将两列数据对比,找出相同的和不同的数据?
  5. JAVA生成随机数种子的方法
  6. iptables导致数据包过多时连接失败
  7. “我爱淘”冲刺阶段Scrum站立会议1
  8. MySQL 索引优化 btree hash rtree
  9. 如何启动 SQL Server Agent(SQL Server 配置管理器)
  10. easyui源码翻译1.32--EasyLoader(简单加载)
  11. iOS开发中使用CIDetector检测人脸
  12. FZU Problem 2150 Fire Game(bfs)
  13. php优化代码技巧
  14. jQuery的Nicescroll滚动条插件使用方法
  15. weblogic部署web项目出现错误
  16. windows下安装mongoDB以及配置启动
  17. MATLAB cftool工具数据拟合结果好坏判断
  18. java核心36
  19. mysql查询用,或#隔开的字段
  20. 准备学习wrf

热门文章

  1. LVS、keepalived原理及配置
  2. vue-cli中vuex IE兼容
  3. JAVAOOP多线程
  4. less学习二---变量
  5. C#中的线程(二)线程同步基础 (读后感)
  6. I/O流、文件操作
  7. BigData--hadoop集群搭建之hbase安装
  8. 5.Python的语言特点
  9. flask迁移
  10. PHP中文乱码分类及解决办法大全