P4568 飛行路線 分層圖最短路
阿新 • • 發佈:2019-05-03
gist 問題 class spl reg cpp define names inline
P4568 飛行路線 分層圖最短路
分層圖最短路
問題模型
求最短路時,可有\(k\)次更改邊權(減為0)
思路
在普通求\(Dijkstra\)基礎上,\(dis[x][j]\)多開一維\(j\)以存已用了多少次機會,然後每次松弛時,做完普通松弛操作後,還要使用一次機會(如果可以),類同\(DP\)。
每次普通松弛:
\[ dis[to][j]=min\{dis[cur][j], dis[to][j]\} \]
如果還可以使用(\(j<k\)):
\[ dis[to][j+1] = min\{dis[cur][j], dis[to][j+1]\} \]
AC Code:
#include <cstdio> #include <vector> #include <cstring> #include <queue> #define MAXN 10010 #define MAXK 11 #define MIN(A,B) ((A)<(B)?(A):(B)) using namespace std; int n,m,k,s,e; bool vis[MAXN][MAXK]; struct edge{ int v,w; edge(int v, int w):v(v),w(w){} }; vector <edge> mp[MAXN]; struct item{ int dis, k, v; item(int dis, int k, int v):dis(dis), k(k), v(v){} bool operator < (const item a) const{ return dis > a.dis; } }; int dis[MAXN][MAXK]; priority_queue <item> q; void Dij(){ memset(dis, 0x3f, sizeof(dis)); dis[s][0]=0; q.push(item(0,0,s)); while(!q.empty()){ item cur = q.top();q.pop(); if(vis[cur.v][cur.k]) continue; vis[cur.v][cur.k] = 1; for(register int i=0;i<mp[cur.v].size();++i){ int v = mp[cur.v][i].v, w = mp[cur.v][i].w; if(cur.k<k&&!vis[v][cur.k+1]&&dis[v][cur.k+1]>dis[cur.v][cur.k]){ // 使用機會 dis[v][cur.k+1] = dis[cur.v][cur.k]; q.push(item(dis[v][cur.k+1], cur.k+1, v)); } if(!vis[v][cur.k]&&dis[v][cur.k]>dis[cur.v][cur.k]+w){ // 普通松弛 dis[v][cur.k] = dis[cur.v][cur.k]+w; q.push(item(dis[v][cur.k], cur.k, v)); } } } } int main() { scanf("%d %d %d %d %d", &n, &m, &k, &s, &e),s++,e++; for(int i=1;i<=m;++i){ int a,b,c; scanf("%d %d %d", &a, &b, &c),++a,++b; mp[a].push_back(edge(b,c)); mp[b].push_back(edge(a,c)); } Dij(); int ans=0x3ffffff; for(int i=0;i<=k;++i) ans = MIN(ans, dis[e][i]); // 遍歷統計答案,機會不一定用完 printf("%d", ans); return 0; }
P4568 飛行路線 分層圖最短路