[USACO09FEB] Revamping Trails 【分层图+Dijkstra】
任意门:https://www.luogu.org/problemnew/show/P2939
Revamping Trails
题目描述
Farmer John dutifully checks on the cows every day. He traverses some of the M (1 <= M <= 50,000) trails conveniently numbered 1..M from pasture 1 all the way out to pasture N (a journey which is always possible for trail maps given in the test data). The N (1 <= N <= 10,000) pastures conveniently numbered 1..N on Farmer John's farm are currently connected by bidirectional dirt trails. Each trail i connects pastures P1_i and P2_i (1 <= P1_i <= N; 1 <= P2_i <= N) and requires T_i (1 <= T_i <= 1,000,000) units of time to traverse.
He wants to revamp some of the trails on his farm to save time on his long journey. Specifically, he will choose K (1 <= K <= 20) trails to turn into highways, which will effectively reduce the trail's traversal time to 0. Help FJ decide which trails to revamp to minimize the resulting time of getting from pasture 1 to N.
TIME LIMIT: 2 seconds
输入输出格式
输入格式:
* Line 1: Three space-separated integers: N, M, and K
* Lines 2..M+1: Line i+1 describes trail i with three space-separated integers: P1_i, P2_i, and T_i
输出格式:
* Line 1: The length of the shortest path after revamping no more than K edges
输入输出样例
说明
K is 1; revamp trail 3->4 to take time 0 instead of 100. The new shortest path is 1->3->4, total traversal time now 1.
题意概括:
给出一个 N 个节点,M 条边的无向图,可以使其中 K 条路径花费为 0 ,求从 点 1 到点 N 的最短路。
解题思路:
分层图,跑一遍优先队列(STL)优化的 Dijkstra。
分层图的含义就是把原图复制 K 层(平行宇宙概念),从下面一层有虫洞到上面一层(即花费为0),通过这种穿越 K 层图的做法达到使其中的 K 条边权值为0.
而现实代码中不需要真的建 K 个图,而是建立一个 dp[ i ][ k ] 保存 1 到 i 穿越了 k 条边的最短路(动态规划的思想,十分巧妙)。
接下来的穿越不同层可以说是状态转移:dp[ to ][ k ] = min( dp[to][k], dp[from][k] + w[edge])
dp[ to ][ k+1 ] = min( dp[ to ][ k+1 ] , dp[ from ][k] )
AC code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //分层图最短路 2 #include <bits/stdc++.h> 3 #define LL long long int 4 #define INF 0x3f3f3f3f 5 using namespace std; 6 //const int INF = 127/3; 7 const int MAXN = 1e4+10; 8 const int MAXK = 23; 9 const int MAXM = 5e4+10; 10 int N, M, K, dis[MAXN][MAXK]; 11 int head[MAXN], node[MAXM<<1], Next[MAXM<<1], w[MAXM<<1], cnt; 12 bool vis[MAXN][MAXK]; 13 14 struct date 15 { 16 int u, k, val; 17 bool operator < (const date& a)const{ //结构体内定义优先队列优化级 18 return val > a.val; 19 } 20 }; 21 priority_queue<date> Q; 22 23 inline void add(int from, int to, int weight) 24 { 25 Next[++cnt] = head[from]; 26 head[from] = cnt; 27 w[cnt] = weight; 28 node[cnt] = to; 29 } 30 31 inline void Dijkstra(int s) 32 { 33 memset(dis, INF, sizeof(dis)); 34 int v; 35 date tp; 36 tp.u = s, tp.k = 0; 37 tp.val = dis[s][0] = 0; 38 Q.push(tp); 39 vis[s][0] = true; 40 while(!Q.empty()){ 41 tp = Q.top(), Q.pop(); 42 vis[tp.u][tp.k] = 0; 43 for(int i = head[tp.u]; i != -1; i = Next[i]){ 44 v = node[i]; 45 if(dis[v][tp.k] > dis[tp.u][tp.k] + w[i]){ 46 dis[v][tp.k] = dis[tp.u][tp.k] + w[i]; 47 if(!vis[v][tp.k]){ 48 Q.push(date{v, tp.k, dis[v][tp.k]}); 49 vis[v][tp.k] = true; 50 } 51 } 52 if(tp.k+1 <= K){ 53 if(dis[v][tp.k+1] > dis[tp.u][tp.k]){ 54 dis[v][tp.k+1] = dis[tp.u][tp.k]; 55 if(!vis[v][tp.k+1]){ 56 Q.push(date{v, tp.k+1, dis[v][tp.k+1]}); 57 vis[v][tp.k+1] = true; 58 } 59 } 60 } 61 } 62 } 63 } 64 void init() 65 { 66 memset(head, -1, sizeof(head)); 67 cnt = 1; 68 } 69 int main() 70 { 71 int u, v, w; 72 scanf("%d%d%d", &N, &M, &K); 73 init(); 74 for(int i = 1; i <= M; i++){ 75 scanf("%d%d%d", &u, &v, &w); 76 add(u, v, w); 77 add(v, u, w); 78 } 79 Dijkstra(1); 80 printf("%d\n", dis[N][K]); 81 return 0; 82 }