[SMOJ1778]青蛙

题目描述

你是一只青蛙,现在处于一个无穷大的网格中,现在你所在的点坐标是 (xMe,yMe),你的目标是跳到点 (xHome,yHome)。你有两种不同的跳跃方式,第一种是:如果你现在的点坐标是 (x,y),你跳一步能跳到相邻的四个点:(x+1,y)(x1,y)(x,y+1) 或者 (x,y1),每跳一步需要一秒;第二种跳跃方式是:使用超级工具 teleport,在整个网格中有 3 个 teleport, 每一个 teleport 连接两个不同的点。 如果你在某个 teleport 的一端,那么你可以使用该 teleport 跳到另一端,需要花费的时间是 10 秒。作为一只青蛙,请输出回家所用的最少时间。注意:teleport 不是强制使用的,你到达某个 teleport 的端点时,你可以不用 teleport 而是用第一种跳跃方式。

输入格式 1778.in

多组测试数据。
第一行,一个整数 Group,表示有 Group 组测试数据。1Groutp5
每组测试数据格式如下:
第一行:四个整数,xMe, yMe, xHome, yHome0xMe,yMe,xHome,yHome109
接下来有三行,每行的格式是:四个整数 x1 y1 x2 y2, 表示有一个 teleport 的两个端点分别是:(x1,y1)(x2,y2)
数据保证:以上读入的 8 个点都不会相同。

输出格式 1778.out

R 行,每行一个整数,青蛙跳到家里的最短时间。

输入样例 1778.in

2
3 3 4 5
1000 1001 1000 1002
1000 1003 1000 1004
1000 1005 1000 1006
0 0 20 20
1 1 18 20
1000 1003 1000 1004
1000 1005 1000 1006

输出样例 1778.out

3
14

样例解释

样例一解释:
from (3,3) to (3,4), then to (3,5), and finally to (4,5).
样例二解释:
Make 2 jumps to get from (0,0) to (1,1), use the teleport to get to (18,20), and make 2 jumps to get to (20,20). This solution takes (2+10+2) = 14 seconds.


这道题目的意思很显然,就是要规划一下路径,使得从起点到终点的费用最小,其中费用定义如下。
路途中每走到 xy 相邻的一格,花费都是 1;
分布有 3 台穿越机,每台穿越机有两个点,可以从其中任意一个点进入,再穿越到另一点,花费为10。

对于一台穿越机,我们要么使用它 1 次,要么不使用它。不可能使用同一台穿越机多于 1 次,这是显然的。因为如果从点 A 穿越到点 B ,再穿越回点 A;或者从点 A 穿越到点 B,再走到点 A,再穿越到点 B,这两种情况都造成了浪费。不可能用两次,那么更加不可能用再多次了。

如此,便可以枚举使用穿越机的顺序。每一步,可以用三台穿越机中的任意一台,或者不用穿越机这四种情况,一共只有 43 种方案。

但是要注意,穿越机的入口和出口是相对的。即使决定了使用某台穿越机,也要分开:从 A 到 B,或从 B 到 A 这两种情况讨论一下。

参考代码:

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

using namespace std;

typedef long long LL;

LL xMe, yMe, xHome, yHome;
LL x1[5], y1[5], x2[5], y2[5];
LL ans;

bool used[5];

inline LL dist(LL X1, LL Y1, LL X2, LL Y2) {
    return abs(X1 - X2) + abs(Y1 - Y2);
}

void dfs(int k, LL lastx, LL lasty, LL sum) {
    if (k == 3) {
        ans = min(ans, sum + dist(lastx, lasty, xHome, yHome));
        return ;
    }
    dfs(k + 1, lastx, lasty, sum);
    for (int i = 0; i < 3; i++)
        if (!used[i]) {
            used[i] = true;
            dfs(k + 1, x2[i], y2[i], sum + dist(lastx, lasty, x1[i], y1[i]) + 10);
            dfs(k + 1, x1[i], y1[i], sum + dist(lastx, lasty, x2[i], y2[i]) + 10);
            used[i] = false;
        }
}

int main(void) {
    freopen("1778.in", "r", stdin);
    freopen("1778.out", "w", stdout);

    int group;
    scanf("%d", &group);
    while (group--) {
        scanf("%lld%lld%lld%lld", &xMe, &yMe, &xHome, &yHome);
        ans = 1LL << 31;
        for (int i = 0; i < 3; i++) scanf("%lld%lld%lld%lld", &x1[i], &y1[i], &x2[i], &y2[i]);
        memset(used, false, sizeof used);
        dfs(0, xMe, yMe, 0);
        printf("%lld\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值