• [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

    输入输出样例

    输入样例#1: 
    4 4 1 
    1 2 10 
    2 4 10 
    1 3 1 
    3 4 100 
    
    输出样例#1: 
    1 
    

    说明

    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:

     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
    ", dis[N][K]);
    81     return 0;
    82 }
    View Code
  • 相关阅读:
    算法(第4版)-1.4.8 处理对于输入的依赖
    设计模式学习笔记之练习代码
    常用算法Java实现之快速排序
    常用算法Java实现之希尔排序
    常用算法Java实现之直接插入排序
    常用算法Java实现之选择排序
    常用算法Java实现之冒泡排序
    Java 集合框架之 Map
    Java 集合框架之Collection
    HBase 参考文档翻译之 Getting Started
  • 原文地址:https://www.cnblogs.com/ymzjj/p/9592252.html
Copyright © 2020-2023  润新知