zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    oracle添加字段,备注
    oracle对日期date类型操作的函数
    查询效率例子收藏
    webuploader.min.js 简单例子
    select 数字/字符串/count(参数)/sum(数字) from table
    oracle常用分析函数 over(partition by xxx order by xxx)
    LigerUi遮罩的两个方法
    LigerUI子父窗口之间传参问题
    LigerUi自动检索输入
    LigerUi折叠与展开
  • 原文地址:https://www.cnblogs.com/ymzjj/p/9592252.html
Copyright © 2011-2022 走看看