【问题描述】
你是一名优秀的水管工。 一天你遇到了一个棘手的难题。 你需要在一个长方体状的房间
内连接一条贯穿房间内部的水管。房间的长为 X,宽为 Y,高为 Z, 整个房间可以看成是 X×Y×Z
个小立方体空间组成的。 如果位房间建立直角坐标系,则房间内每个小立方体空间都可以用
一个三维坐标(x,y,z)表示, 房间一角的小立方体的坐标为(1,1,1), 它的对角的坐标为(X,Y,Z),
其余小立方体的坐标的三个维度都分别落在 1…X, 1…Y 和 1…Z 内。 水管的入口和出口已经
开凿好了,它们位于长方体的表面(可能位于房间的地板、墙壁或天花板上),且正好占据
了某个小立方体的一个面。下图展示了房间的立方体空间的划分方式和一种开凿水管出入口
的方式。

你的手头只有一种形状的水管部件, 它呈 L 型,且正好占据了 4 个小立方体空间, 如下
图所示, 灰色部分是水管部件两端的开口位置。

你可以任意旋转、翻转水管部件,然后将它的开口接到入口、 出口或者其它水管部件的
开口上。 水管的开口必须正好接在入口或出口上才算接上,伸出房间外一截是不行的。 下图
展示了一种两个水管部件的连接方式。

在连接水管时, 水管部件间不能相交,也不能伸出房间之外。房间内有一些小立方体空
间已经被物品占据了,水管也不能经过那些格子。 另外,水管部件数量有限,你的手头只有
12 个这样的零件。
现在,给出房间的长、高、 宽, 以及入口、出口的位置和房间内物品的坐标,请你计算 至少需要多少个这样的水管部件才能完成任务,或者判断无法完成任务。
【输入】
输入的第 1 行包含 4 个正整数 X, Y, Z, m,其中 X,Y,Z 表示房间的长、高、宽, m 表示
房间中物品的数量。
输入的第 2 行包含 3 个正整数 x1, y1, z1, 和一个字符 ch。 其中(x1,y1,z1)是水管入口所
在的小立方体的坐标。 ch 的值为'x'、 'y'或'z', 用于指示入口所在的面。 当 ch 为'x'时,表示
入口所在的面与 YZ 坐标平面平行, 当 ch 为'y'时,表示入口所在的面与 XZ 坐标平面平行,
当 ch 为'z'时,表示入口所在的面与 XY 坐标平面平行。 输入保证入口所在的面在长方体表面
上。 数字和数字、数字和字符间用一个空格隔开。
输入的第 3 行包含 3 个正整数 x2, y2, z2,和一个字符 ch, 表示水管出口的位置, 意义
与格式同上。
接下来 m 行,每行包含三个正整数 xi, yi, zi,表示在坐标(xi,yi,zi)的小立方体空间内有
物品。
【输出】
输出包含 1 个整数,表示最少使用的水管部件的数量。 如果不能完成接水管的任务,输
出“impossible”, 不含引号。
【输入输出样例 1】

plumber.in plumber.out
5 4 3 1
3 1 1 z
1 4 3 x
2 3 3
2

见选手目录下的 plumber/plumber1.in 与 plumber/plumber1.out
【输入输出样例 1 说明】
入口和出口的位置如图所示:

分析:就是一道爆搜题.dfs,记录放的水管的最后一个位置和方向,除了这个方向和它对面的方向以外都可以放,然后就有两种方式了,讨论一下,枚举一下旋转方向就行了.

直接搜会T掉,要加上剪枝.可行性剪枝似乎不行,考虑最优性剪枝,如果剪枝仅仅是如果当前用的水管数>ans就返回,还是会T掉4个点,需要用上一个估价函数.考虑3维空间上的曼哈顿距离,每用一个水管当前位置与终点位置的曼哈顿距离就会-4,计算一下当前点与终点的曼哈顿距离为多少就能计算出至少还需要用多少根水管,就能最优性剪枝了.

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; const int dx[] = { , -, , , , }, dy[] = { , , , -, , }, dz[] = { , , , , , - }; int X, Y, Z, m, ans = , tx, ty, tz, tdir, sx, sy, sz, sdir;
bool vis[][][], a[][][]; bool check(int x, int y, int z)
{
if (x >= && x <= X && y >= && y <= Y && z >= && z <= Z && !vis[x][y][z] && !a[x][y][z])
return true;
return false;
} void dfs(int x, int y, int z, int dir, int p)
{
int dis = abs(tx - x) + abs(ty - y) + abs(tz - z);
if (p + dis / >= ans)
return;
if (x == tx && y == ty && z == tz && dir == tdir)
{
ans = min(ans, p);
return;
}
if (check(x + dx[dir], y + dy[dir], z + dz[dir]) && check(x + * dx[dir], y + * dy[dir], z + * dz[dir]))
{
vis[x + dx[dir]][y + dy[dir]][z + dz[dir]] = ;
vis[x + * dx[dir]][y + * dy[dir]][z + * dz[dir]] = ;
int nx = x + * dx[dir], ny = y + * dy[dir], nz = z + * dz[dir];
for (int i = ; i < ; i++)
{
if ((i / ) != (dir / ))
{
if (check(nx + dx[i], ny + dy[i], nz + dz[i]) && check(nx + * dx[i], ny + * dy[i], nz + * dz[i]))
{
vis[nx + dx[i]][ny + dy[i]][nz + dz[i]] = vis[nx + * dx[i]][ny + * dy[i]][nz + * dz[i]] = ;
dfs(nx + * dx[i], ny + * dy[i], nz + * dz[i], i, p + );
vis[nx + dx[i]][ny + dy[i]][nz + dz[i]] = vis[nx + * dx[i]][ny + * dy[i]][nz + * dz[i]] = ;
}
}
} if (check(x + * dx[dir], y + * dy[dir], z + * dz[dir]))
{
vis[x + * dx[dir]][y + * dy[dir]][z + * dz[dir]] = ;
int nx = x + * dx[dir], ny = y + * dy[dir], nz = z + * dz[dir];
for (int i = ; i < ; i++)
{
if ((i / ) != (dir / ))
{
if (check(nx + dx[i], ny + dy[i], nz + dz[i]))
{
vis[nx + dx[i]][ny + dy[i]][nz + dz[i]] = ;
dfs(nx + dx[i], ny + dy[i], nz + dz[i], i, p + );
vis[nx + dx[i]][ny + dy[i]][nz + dz[i]] = ;
}
}
}
vis[x + * dx[dir]][y + * dy[dir]][z + * dz[dir]] = ;
}
vis[x + dx[dir]][y + dy[dir]][z + dz[dir]] = ;
vis[x + * dx[dir]][y + * dy[dir]][z + * dz[dir]] = ;
}
} int main()
{
scanf("%d%d%d%d", &X, &Y, &Z, &m);
char s[];
scanf("%d%d%d", &sx, &sy, &sz);
scanf("%s", s);
sdir = (s[] - 'x') * ; //找起点
if (s[] == 'x')
sdir += (sx == X);
else
if (s[] == 'y')
sdir += (sy == Y);
else
if (s[] == 'z')
sdir += (sz == Z);
sx -= dx[sdir];
sy -= dy[sdir];
sz -= dz[sdir];
scanf("%d%d%d", &tx, &ty, &tz);
scanf("%s", s);
tdir = (s[] - 'x') * ;
if (s[] == 'x')
tdir += (tx == );
else
if (s[] == 'y')
tdir += (ty == );
else
if (s[] == 'z')
tdir += (tz == );
for (int i = ; i <= m; i++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
a[x][y][z] = ;
}
dfs(sx, sy, sz, sdir, );
if (ans == )
printf("impossible\n");
else
printf("%d\n", ans); return ;
}

noip模拟赛 水管工的难题的更多相关文章

  1. noip模拟赛 水题

    题目描述 LYK出了道水题. 这个水题是这样的:有两副牌,每副牌都有n张. 对于第一副牌的每张牌长和宽分别是xi和yi.对于第二副牌的每张牌长和宽分别是aj和bj.第一副牌的第i张牌能覆盖第二副牌的第 ...

  2. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  3. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  4. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  5. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  6. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  7. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  8. 10.17 NOIP模拟赛

    目录 2018.10.17 NOIP模拟赛 A 咒语curse B 神光light(二分 DP) C 迷宫maze(次短路) 考试代码 B 2018.10.17 NOIP模拟赛 时间:1h15min( ...

  9. 10.16 NOIP模拟赛

    目录 2018.10.16 NOIP模拟赛 A 购物shop B 期望exp(DP 期望 按位计算) C 魔法迷宫maze(状压 暴力) 考试代码 C 2018.10.16 NOIP模拟赛 时间:2h ...

随机推荐

  1. 双栈排序 2008年NOIP全国联赛提高组(二分图染色)

    双栈排序 2008年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master     题目描述 Description Tom最近在研究一个有 ...

  2. 爬虫—Selenium使用

    Selenium使用 Selenium是一个自动化测试工具,可以驱动浏览器器执行特定的动作,如点击,下拉等.同时还可以获取浏览器当前呈现页面的源代码,可见即可爬. 1.准备 我们使用谷歌Chrome浏 ...

  3. knockout 和mvc4结合使用

    Knockout (或者Knockout.js ,KnockoutJS)是一个开源的JavaScript库,网址为www.knockoutjs.com.Knockout语法简洁.可读性好,能轻松实现与 ...

  4. 贪心 Codeforces Round #191 (Div. 2) A. Flipping Game

    题目传送门 /* 贪心:暴力贪心水水 */ #include <cstdio> #include <algorithm> #include <cstring> us ...

  5. 聊聊MyBatis缓存机制

    https://tech.meituan.com/mybatis_cache.html 前言 MyBatis是常见的Java数据库访问层框架.在日常工作中,开发人员多数情况下是使用MyBatis的默认 ...

  6. c# Queue实现生产者(Producer)消费者(Consumer)模式

    我们在开发过程中经常会遇到需要从一个地方不断获取数据然后又需要交给另一个线程对数据进行二次加工的情况,这种场景适合使用生产者-消费者模式. Demo展示 //中间的容器 public static c ...

  7. Android基础TOP5_4:点击按钮更换样式,设置透明度

    在res/drawable创建两个样式 点击前/点击后 round: <?xml version="1.0" encoding="utf-8"?> ...

  8. Navicat Premium 12 破解方法

    基本安装下一步下一步,破解方法参考:地址

  9. setTimeout 0

    setTimeout 0 就是把事件放到下一次事件循环时调用,至少要一个时钟之后: ); console.log('this should before setTimeout 0'); var i=0 ...

  10. 关于 . H 宏定义技巧

    #ifndef   LABEL #define   LABEL //代码部分 #endif LABEL为一个唯一的标号,命名规则跟变量的命名规则一样.常根据它所在的头文件名来命名,例如,如果头文件的文 ...