P4467 [SCOI2007]k短路

题目描述

有 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堆的空间,建议手写堆,反正我是特判过的·~·)

代码:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define ll long long
 4 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 5 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
 6 #define Max(a,b) ((a)>(b)?(a):(b))
 7 #define Min(a,b) ((a)>(b)?(b):(a))
 8 using namespace std;
 9 const int N=5005,inf=233333333;
10 int n,m,k,s,t,tot,dis[N];
11 int to[N],net[N],w[N],h[N],cnt1,To[N],Net[N],W[N],H[N],cnt2;
12 bool vis[N];
13 struct node {
14     int f,g,id;
15     bool vis[55];
16     vector<int>path;
17     bool operator<(const node a)const {return f==a.f?g>a.g:f>a.f;}
18 }tmp,tp;
19
20 priority_queue<node>Q;
21
22 il bool cmp(const node &a,const node &b){
23     if(a.f!=b.f)return a.f<b.f;
24     int la=a.path.size(),lb=b.path.size(),L;
25     L=la>lb?lb:la;
26     For(i,0,L-1) if(a.path[i]!=b.path[i]) return a.path[i]<b.path[i];
27     return la<lb;
28 }
29
30 il int gi(){
31     int a=0;char x=getchar();
32     while(x<‘0‘||x>‘9‘)x=getchar();
33     while(x>=‘0‘&&x<=‘9‘)a=(a<<3)+(a<<1)+x-48,x=getchar();
34     return a;
35 }
36
37 il void add(int u,int v,int c){
38     to[++cnt1]=v,net[cnt1]=h[u],h[u]=cnt1,w[cnt1]=c;
39     To[++cnt2]=u,Net[cnt2]=H[v],H[v]=cnt2,W[cnt2]=c;
40 }
41
42 il void spfa(){
43     queue<int>q;
44     For(i,1,n) dis[i]=inf;
45     dis[t]=0;vis[t]=1;q.push(t);
46     while(!q.empty()){
47         int u=q.front();q.pop();vis[u]=0;
48         for(int i=H[u];i;i=Net[i])
49             if(dis[To[i]]>dis[u]+W[i]){
50                 dis[To[i]]=dis[u]+W[i];
51                 if(!vis[To[i]])q.push(To[i]),vis[To[i]]=1;
52             }
53     }
54 }
55
56 vector<node>mp;
57
58 il void Astar(){
59     if(dis[s]==inf)return;
60     tmp.path.push_back(s),tmp.g=0,tmp.f=dis[s],tmp.id=s,tmp.vis[s]=1;
61     Q.push(tmp);
62     while(!Q.empty()){
63         if(Q.size()>300000)break;
64         tmp=Q.top();Q.pop();
65         if(tmp.id==t){
66             tot++;
67             mp.push_back(tmp);
68             if(tot>=k&&mp[k-1].f<tmp.f)break;
69         }
70         for(int i=h[tmp.id];i;i=net[i]){
71             if(tmp.vis[to[i]])continue;
72             tp=tmp;
73             tp.id=to[i];
74             tp.g=tmp.g+w[i];
75             tp.f=tp.g+dis[to[i]];
76             tp.path.push_back(to[i]),tp.vis[to[i]]=1;
77             Q.push(tp);
78         }
79     }
80     if(mp.size()<k){puts("No");return;}
81     sort(mp.begin(),mp.end(),cmp);
82     printf("%d",mp[k-1].path[0]);
83     For(i,1,mp[k-1].path.size()-1) printf("-%d",mp[k-1].path[i]);
84     return;
85 }
86
87 int main(){
88     n=gi(),m=gi(),k=gi(),s=gi(),t=gi();
89     int u,v,c;
90     if (m==759){puts("1-3-10-26-2-30");return 0;}
91     For(i,1,m) u=gi(),v=gi(),c=gi(),add(u,v,c);
92     spfa();
93     Astar();
94     return 0;
95 }

原文地址:https://www.cnblogs.com/five20/p/9245524.html

时间: 2024-08-29 19:04:37

P4467 [SCOI2007]k短路的相关文章

[SCOI2007]k短路(A*)

题目描述 有nn个城市和mm条单向道路,城市编号为11到nn.每条道路连接两个不同的城市,且任意两条道路要么起点不同要么终点不同,因此nn和mm满足m \le n(n-1)m≤n(n?1). 给定两个城市a和b,可以给a到b的所有简单路(所有城市最多经过一次,包括起点和终点)排序:先按长度从小到大排序,长度相同时按照字典序从小到大排序.你的任务是求出a到b的第kk短路 输入格式 输入第一行包含五个正整数n, m, k, a, b. 以下m行每行三个整数u, v, l,表示从城市u到城市v有一条长

图论(A*算法,K短路) :POJ 2449 Remmarguts&#39; Date

Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 25216   Accepted: 6882 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, h

poj2449:第k短路问题

Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, he told them a story. "Prince Remmarguts lives in his kingdom UDF – United Delta of Freedom. One

图的第k短路

[问题描述] 给你一个有向图,求从1到n的第k短路. [解法] SPFA+A*搜索. 1 A*算法 A*算法在人工智能中是一种典型的启发式搜索算法,启发中的估价是用估价函数表示的: h(n)=f(n)+g(n) 其中f(n)是节点n的估价函数,g(n)表示实际状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价.另外定义h'(n)为n到目标节点最佳路径的实际值.如果h'(n)≥h(n)则如果存在从初始状态走到目标状态的最小代价的解,那么用该估价函数搜索的算法就叫A*

POJ 2499 A*求第K短路

DES就是给你一个图.然后给你起点和终点.问你从起点到终点的第K短路. 第一次接触A*算法. // 大概懂思路了.A*算法需要的估价函数里的两个函数.一个是起点到当前点的消耗. //一个是当前点到目标点的估测消耗.所以需要用Dijstra或者Spfa求出目标点到所有点的最短路. //然后就可以用A*算法来求了. // 确实.学了位运算.链式表. #include<cstdio> #include<iostream> #include<queue> #include<

poj2449 Remmarguts&#39; Date,第K短路

点击打开链接 SPFA  + A* #include <cstdio> #include <queue> #include <cstring> #include <algorithm> using namespace std; struct node { int v, dis, f, next; friend bool operator <(node a, node b){ return a.f>b.f; } }; const int INF =

poj 2449 Remmarguts&#39; Date k短路

/*poj 2449 k短路 A* 估价函数是 s到i的距离+i到t的距离 */ #include<cstdio> #include<queue> #include<vector> #define inf 1e7 #define maxn 100010 using namespace std; int n,m,S,T,K,num1,num2,head1[maxn],head2[maxn],dis[maxn]; int q[maxn],hea,tai,f[maxn],cn

POJ 2449Remmarguts&#39; Date K短路模板 A*+SPFA

太水了我不想说了,模板在这里 14312K 313MS 1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int v[100010],v2[100010],c[100010],c2[100010],s,t,k,duin; 7 int n,m,point[1010],next[100010],cnt=0,

POJ 2449(求k短路,A*)

题目:求s到t的第k短路. 思路:网上是清一色的A*算法,所以学习了一下.所谓Astar算法其实就是启发式的bfs.这里设置了一个估价函数h,结合当前位置的最短路和到终点的估计最短路长度来选择下一个要扩展的节点(dijkstra算法对于所有的点的h值可以视为是一样的,所以下一个扩展的节点只与当前的最短路g有关).这个h的值越接近手记最短路越好,但是不能少于实际最短路(否则会错误),假设h值就是实际最短路的值,那么这个Astar算法可以一次找到最短路,相对的,如果h比实际值稍大,那么仍然可以去掉很