zoukankan      html  css  js  c++  java
  • ZOJ 1232 Adventure of Super Mario (Floyd + DP)

    题意:有a个村庄,编号为1到a,有b个城堡,编号为a+1到a+b。现在超级玛丽在a+b处,他的家在1处。每条路是双向的,两端地点的编号以及路的长度都已给出。路的长度和通过所需时间相等。他有一双鞋子,可以使用k次,每次使用后最多可以跑过l的距离,且通过这段距离所需时间为0。使用鞋子时,必须从村庄或城堡开始,到村庄或者城堡结束。但是,城堡充满了陷阱,他如果中途遇见城堡,就必须停下来,且鞋子视为使用完了一次。问超级玛丽回家所需的最短时间。

    思路:用floyd算法先处理出任意两点间的最短距离(不用鞋子时)。另用一个二维数组来维护两点之间是否允许用鞋子直接传送。当两点最短距离不大于l且中间不经过城堡时,数组值为真。

    然后,进行dp。dp[i][k]表示从1到i用了k次鞋子时的最短时间(边是双向的,从1开始和从a+b开始是等价的)。

    dp[i][k] = min(dp[j][k-1], dp[j][k])。当j到i不允许穿鞋子时,只有后面一项。最后dp[a+b][k]即为最终结果。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #define inf 0x3f3f3f3f
     5 #define maxn 105
     6 using namespace std;
     7 int a, b, m, l, tk;
     8 int d[maxn][maxn], ok[maxn][maxn], dp[maxn][12];
     9 void floyd()
    10 {
    11     for (int k = 1; k <= a + b; k++)
    12         for (int i = 1; i <= a + b; i++)
    13             for (int j = 1; j <= a + b; j++)
    14                 if (d[i][j] > d[i][k] + d[k][j])
    15                 {
    16                     d[i][j] = d[i][k] + d[k][j];
    17                     if (k <= a && d[i][j] <= l) ok[i][j] = ok[j][i] = 1;
    18                 }
    19 }
    20 void run_dp()
    21 {
    22     for (int i = 1; i <= a + b; i++)
    23         dp[i][0] = d[1][i];
    24     for (int i = 0; i <= tk; i++)
    25         dp[1][i] = 0;
    26     for (int i = 2; i <= a + b; i++)
    27         for (int k = 1; k <= tk; k++)
    28         {
    29             int tmin = inf;
    30             for (int j = 1; j < i; j++)
    31             {
    32                 if (ok[j][i])
    33                     tmin = min(tmin, dp[j][k-1]);
    34                 tmin = min(tmin, dp[j][k] + d[j][i]);
    35             }
    36             dp[i][k] = tmin;
    37         }
    38 }
    39 int main()
    40 {
    41     int t;
    42     //freopen("data.in", "r", stdin);
    43     scanf("%d", &t);
    44     while (t--)
    45     {
    46         scanf("%d%d%d%d%d",&a,&b,&m,&l,&tk);
    47         memset(d, 0x3f, sizeof(d));
    48         memset(ok, 0, sizeof(ok));
    49         while (m--)
    50         {
    51             int u, v, w;
    52             scanf("%d%d%d",&u,&v,&w);
    53             d[u][v] = d[v][u] = w;
    54             if (w <= l) ok[u][v] = ok[v][u] = 1;
    55         }
    56         floyd();
    57         run_dp();
    58         printf("%d
    ",dp[a+b][tk]);
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    前端开发中一些好用的软件包。
    LeetCode 26 删除排序数组中的重复项
    算法 主定理
    算法学习计划继续三四个月
    Web Api
    DOM viewport
    CSS OM
    DOM Range Api
    DOM 操作 2
    DOM Event
  • 原文地址:https://www.cnblogs.com/fenshen371/p/3243623.html
Copyright © 2011-2022 走看看