p4568 [JLOI2011]飛行路線
阿新 • • 發佈:2018-10-07
ans use code 表示 直接 城市 string cst 現在
Description
Alice和Bob現在要乘飛機旅行,他們選擇了一家相對便宜的航空公司。該航空公司一共在nn個城市設有業務,設這些城市分別標記為\(0\)到\(n?1\),一共有\(m\)種航線,每種航線連接兩個城市,並且航線有一定的價格。
Alice和Bob現在要從一個城市沿著航線到達另一個城市,途中可以進行轉機。航空公司對他們這次旅行也推出優惠,他們可以免費在最多\(k\)種航線上搭乘飛機。那麽Alice和Bob這次出行最少花費多少?
Input
數據的第一行有三個整數,\(n,m,k\),分別表示城市數,航線數和免費乘坐次數。
第二行有兩個整數,\(s,t\),分別表示他們出行的起點城市編號和終點城市編號。
接下來有\(m\)行,每行三個整數,\(a,b,c\),表示存在一種航線,能從城市\(a\)到達城市\(b\),或從城市\(b\)到達城市\(a\),價格為\(c\)。
Output
只有一行,包含一個整數,為最少花費
分析
? 明顯,此題為最短路問題,但是考慮到可以免費搭乘(即直接通過一條邊無需費用.)
這種問題有一個較官方的名字 分層圖最短路問題
分層圖最短路是指在可以進行分層圖的圖上解決最短路問題.
是不是聽起來就很nb?
具體分層圖是啥,我也不知道
一般模型:
? 在圖上,有\(k\)次機會可以直接通過一條邊,問起點與終點之間的最短路徑.
很明顯,這道題是一個裸的分層圖最短路問題 (貌似這類問題都挺裸的 emm
解法
我們設
\(dis[i][j]\)代表到達\(i\)用了\(j\)次免費機會的最小花費.
\(vis[i][j]\)代表到達\(i\)用了\(j\)次免費機會的情況是否出現過.
對於某條路徑我們可以選擇使用機會,也可以選擇不使用機會.
討論這兩種情況即可
#include<cstdio> #include<queue> #include<cstring> #define R register #define N 20008 using namespace std; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(s>'9' or s<'0'){if(s=='-')f=-1;s=getchar();} while(s>='0' and s<='9'){x=x*10+s-'0';s=getchar();} x*=f; } int head[N],tot,n,m,s,t,k; int dis[N][15],ans=2147483647; bool vis[N][15]; struct cod{int u,v,w;}edge[N*6+8]; inline void add(int x,int y,int z) { edge[++tot].u=head[x]; edge[tot].v=y; edge[tot].w=z; head[x]=tot; } struct coc{ int u,d,used; bool operator <(const coc&a) const { return d>a.d; } }; inline void dijkstra() { memset(dis,127,sizeof dis); dis[s][0]=0; priority_queue<coc>q; q.push((coc){s,0,0}); while(!q.empty()) { int u=q.top().u,now=q.top().used; q.pop(); if(vis[u][now])continue; vis[u][now]=true; for(R int i=head[u];i;i=edge[i].u) { if(now<k and !vis[edge[i].v][now+1] and dis[edge[i].v][now+1]>dis[u][now])//當前路徑,使用一次免費機會.註意判斷 now<k { dis[edge[i].v][now+1]=dis[u][now]; q.push((coc){edge[i].v,dis[edge[i].v][now+1],now+1}); } if(!vis[edge[i].v][now] and dis[edge[i].v][now]>dis[u][now]+edge[i].w)//當前路徑,不使用免費機會 { dis[edge[i].v][now]=dis[u][now]+edge[i].w; q.push((coc){edge[i].v,dis[edge[i].v][now],now}); } } } } int main() { in(n),in(m),in(k); in(s),in(t); s++;t++;//這裏個人習慣不同.我選擇記錄編號為1~n for(R int i=1,x,y,z;i<=m;i++) { in(x),in(y),in(z); x++;y++; add(x,y,z); add(y,x,z); } dijkstra();//直接跑dijkstra for(R int i=0;i<=k;i++) ans=min(ans,dis[t][i]);//到達t我們需要對使用免費機會的情況枚舉.取min printf("%d",ans); }
p4568 [JLOI2011]飛行路線