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\n",dp[a+b][tk]);

59     }

60     return 0;

61 }

 

 

 

你可能感兴趣的:(super)