Adventure of Super Mario——UVA 10269(最短路)

Adventure of Super Mario
题目描述:
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.


题目大意:

马里奥要去营救公主。前A个点是村庄,后B个点是城堡 。起始位置是1点,终点是A+B。要求一个最短路。
但是马里奥有一双飞行鞋,可以飞最多L的距离,并且飞行的起点和终点必须在村庄或者城堡上。而且飞行不能经过城堡(不算起点和终点)。飞行鞋最多可以飞K次。

思路分析:

首先可以以确定这是一道最短路题目。而且容易想到用三维状态来表示节点的状态:
used[u][jump][times]
表示在u点已跳跃jump距离且用掉了time次飞行的距离。
接着就是如何转移这个状态的问题,个人认为这个比构造上面的状态麻烦。


首先是不采用飞行:
dis[v][0][times] = dis[u][jump][times]+es[i].len;

然后就是采用飞行(也就是起飞):
dis[v][es[i].len][times+1]  = dis[u][jump][times];     (es[i].len <= l && times+1 <= k)
最后就是飞行的转移:
dis[v][jump+es[i].len][times] = dis[u][jump][times]  (es[i].len+jump <= l && u <= a && jump)
上面的判断是重要部分:因为不能穿过B区域的点,所以需要判断起点需要为A区域的点,才能做飞行转移。

代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cctype>
#include <queue>
#include <map>
#include <algorithm>
#define LL long long
#define maxm 2001*2001*12+2002
#define maxn 202
#define maxp 2001*2001
using namespace std;
#define INF 0x7f7f7f7f
struct Node
{
    int u,len,jump,times;
    bool operator < (const Node b) const
    {
        return len > b.len;
    }
};
struct Edge
{
    int from,to,len,next;
}es[maxm];
int used[102][520][12];
int a,b,m,l,k;
int cnt,p[2*100*100*2];
void add(int x,int y,int len)
{
    es[cnt].from = x;
    es[cnt].to = y;
    es[cnt].len = len;
    es[cnt].next = p[x];
    p[x] = cnt++;

    es[cnt].from = y;
    es[cnt].to = x;
    es[cnt].len = len;
    es[cnt].next = p[y];
    p[y] = cnt++;
}
void init()
{
    memset(p,-1,sizeof p);
    cnt = 0;
}
int dij(int s,int t)
{
    memset(used,0,sizeof used);
    priority_queue<Node> q;
    q.push((Node){s,0,0,0});
    while(!q.empty())
    {
        Node x = q.top();
        q.pop();
        int u = x.u;
        int jump = x.jump;
        int times = x.times;
        used[u][jump][times] = 1;
        if(u == t) return x.len;

        for(int i  = p[u];i+1;i = es[i].next)
        {
            int v = es[i].to;
            if(jump+es[i].len <= l && u <= a && jump)
            {
                if(!used[v][jump+es[i].len][times])
                    q.push((Node){v,x.len,jump+es[i].len,times});
            }
            if(es[i].len <= l && times +1 <= k && !used[v][es[i].len][times+1])
                q.push((Node){v,x.len,es[i].len,times+1});
            if(!used[v][0][times])
               q.push((Node){v,x.len+es[i].len,0,times});

        }
    }
}
int main()
{

    int T;
    scanf("%d",&T);
    for(int ks = 1;ks <= T;ks++)
    {
        init();
        scanf("%d %d %d %d %d",&a,&b,&m,&l,&k);
        for(int i = 1;i <= m;i++)
        {
            int x,y,len;
            scanf("%d %d %d",&x,&y,&len);
            add(x,y,len);
        }
        printf("%d\n",dij(1,a+b));
    }
    return 0;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值