UVA10269 Adventure of Super Mario(Floyd+DP)

UVA10269 Adventure of Super Mario(Floyd+DP)

After rescuing the beautiful princess, Super Mario needs to find a way home -- with the princess of course :-) He's very familiar with the 'Super Mario World', so he doesn't need a map, he only needs the best route in order to save time.

 

There are A Villages and B Castles in the world. Villages are numbered 1..A, and Castles are numbered A+1..A+B. Mario lives in Village 1, and the castle he starts from is numbered A+B. Also, there are two-way roads connecting them. Two places are connected by at most one road and a place never has a road connecting to itself. Mario has already measured the length of every road, but they don't want to walk all the time, since he walks one unit time for one unit distance(how slow!).

Luckily, in the Castle where he saved the princess, Mario found a magic boot. If he wears it, he can super-run from one place to another IN NO TIME. (Don't worry about the princess, Mario has found a way to take her with him when super-running, but he wouldn't tell you :-P)

Since there are traps in the Castles, Mario NEVER super-runs through a Castle. He always stops when there is a castle on the way. Also, he starts/stops super-runnings ONLY at Villages or Castles.

Unfortunately, the magic boot is too old, so he cannot use it to cover more than L kilometers at a time, and he cannot use more than K times in total. When he comes back home, he can have it repaired and make it usable again.


Input

The first line in the input contains a single integer T, indicating the number of test cases. (1<=T<=20) Each test case begins with five integers A, B, M, L and K -- the number of Villages, the number of Castles(1<=A,B<=50), the number of roads, the maximal distance that can be covered at a time(1<=L<=500), and the number of times the boot can be used. (0<=K<=10) The next M lines each contains three integers Xi, Yi, Li. That means there is a road connecting place Xi and Yi. The distance is Li, so the walk time is also Li. (1<=Li<=100)


Output

For each test case in the input print a line containing a single integer indicating the minimal time needed to go home with the beautiful princess. It's guaranteed that Super Mario can always go home.


Sample Input

1
4 2 6 9 1
4 6 1
5 6 10
4 5 5
3 5 4
2 3 4
1 2 3

Sample Output

9

题目大意

已知A+B个顶点的一张简单图,其中A个顶点标示为村庄,B个顶点标示为城堡,求顶点1到顶点A+B的一条最短路径,但是过程中允许使用K次魔法鞋,每次使用可以在0的时间内移动L个单位,中途遇到城堡将停止魔法,使用魔法鞋的起点和终点都只能是城堡或者村庄。

 

解题报告

这道题目一开始想到最短路,可是不知道怎么处理使用魔法鞋的情况。在网上看了神犇的博客才知道解法,其实是Floyd+dp 首先,用Floyd处理任意两点间距离,开一个数组,在处理时判断是否能用魔法鞋走,即g[i][j]<=L&&k<=A,那么can[i][j]=1 。然后,再用dp处理。用数组dis[i][k] 表示走到地i个点,用了k次魔法的最小值。状态转移方程为 dis[j][k-1] (i与j之间可用魔法鞋)

$dis[i][k]=min{sumlimits_{j=1}^{i-1}dis[j][h]+g[j][i]}$

初始状态 dis[i][0]=g[s][i] (i=1 to a+b)   dis[1][i]=0 i=0 to K

最后dis[A+B][K] 即为结果。

#include<queue>
#include <algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define Pair pair<int,int>
#define MAXN 101
#define MAX 99999999
using namespace std;
int t,a,b,m,l,k,g[MAXN][MAXN],can[MAXN][MAXN];
int dis[MAXN][MAXN];
void init()
{
    memset(can,0,sizeof(can));
    memset(g,32,sizeof(g));
    memset(dis,0,sizeof(dis));
    scanf("%d%d%d%d%d",&a,&b,&m,&l,&k);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        g[x][y]=g[y][x]=z;
        if(z<=l) can[x][y]=can[y][x]=1;
    }
}
void floyed()
{
    for(int i=1;i<=a+b;i++) g[i][i]=0;
    for(int k=1;k<=a+b;k++)
        for(int i=1;i<=a+b;i++)
            for(int j=1;j<=a+b;j++)
                if(g[i][j]>g[i][k]+g[k][j])
                {
                     g[i][j]=g[i][k]+g[k][j];
                     if(k<=a&&g[i][j]<=l) can[i][j]=can[j][i]=1;
                }
                     
}
void dp(int s)
{
    for(int i=1;i<=a+b;i++) dis[i][0]=g[s][i];
    for(int i=0;i<=k;i++) dis[s][i]=0;
    for(int i=2;i<=a+b;i++) 
        for(int h=1;h<=k;h++)
        {
            int minn=MAX;
            for(int j=1;j<i;j++)
            {
                if(can[i][j]) minn=min(minn,dis[j][h-1]);
                minn=min(minn,dis[j][h]+g[j][i]);
            }
            dis[i][h]=minn;
        }
}

int main()
{

    scanf("%d",&t);
    while(t--)
    {
        init();
        floyed();
        dp(1);
        printf("%d
",dis[a+b][k]);
    }
    return 0;
}

(对于我来说算是个难题了==)

原文地址:https://www.cnblogs.com/yangyaojia/p/6346487.html