1. 程式人生 > >P4467 [SCOI2007]k短路

P4467 [SCOI2007]k短路

遍歷 define har 說明 -- 100% min close lin

題目描述

n 個城市和 m 條單向道路,城市編號為 1 到 n 。每條道路連接兩個不同的城市,且任意兩條道路要麽起點不同要麽終點不同,因此 nm 滿足 m \le n(n-1)mn(n1) 。

給定兩個城市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 }

P4467 [SCOI2007]k短路