【问题描述】
你是一名优秀的水管工。 一天你遇到了一个棘手的难题。 你需要在一个长方体状的房间
内连接一条贯穿房间内部的水管。房间的长为 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. poj 2154 Color【polya定理+欧拉函数】

    根据polya定理,答案应该是 \[ \frac{1}{n}\sum_{i=1}^{n}n^{gcd(i,n)} \] 但是这个显然不能直接求,因为n是1e9级别的,所以推一波式子: \[ \frac ...

  2. 启动VMware环境下的Linux操作系统,添加新分区

    启动VMware环境下的Linux操作系统,添加新分区,需要root账号身份. 3.1 [fdisk -l] 最大分区为/dev/sda3,说明新创建的分区将会是sda4 3.2 输入[fdisk / ...

  3. [SHOI2013]超级跳马

    题目描述 现有一个n 行m 列的棋盘,一只马欲从棋盘的左上角跳到右下角.每一步它向右跳奇数列,且跳到本行或相邻行.跳越期间,马不能离开棋盘.试求跳法种数mod 30011. 输入输出格式 输入格式: ...

  4. 每天学点Linux命令: 管道| 与 xargs的区别

    先看一个例子: find ./ -print | xargs grep a 输出: grep: ./: 是一个目录 ./less:abc ./afile:abcde ./afile:AaAbBcB . ...

  5. 数据库学习:for xml path

    一.开发环境 数据库:SQLServer2012 二.语法简介 for xml path它以xml形式展示查询的结果集 三.语法介绍 现在数据库中有一张表 1.基本语法 select * from B ...

  6. IDEA破解方法以及快捷键大全

    IntelliJ IDEA2017.3 激活 - CSDN博客:https://blog.csdn.net/dc2222333/article/details/78582131 Eclipse和Int ...

  7. 安装linux mint 18.3 后要做的

    使用u盘安装的linux mint 18.3,安装过程基本顺利 发现在安装过程中使用中文语言的话会使得下载附加软件的速度快很多 安装完成之后要做的事情有: 1.字体 默认的楷体字比较难看,在软件管理器 ...

  8. ProcessBar 与SeekBar进度条

    1.进度条关键属性 2.进度条的常用方法 progress = (ProgressBar) findViewById(R.id.horiz); (1)获取第一进度条:progress.getProgr ...

  9. 【Python-2.7】删除空格

    有时我们在编程过程中,需要去除字符串两边的空格,可以用如下函数解决问题: rstrip():去除字符串右边的空格: lstrip():去除字符串左边的空格: strip():去除字符串两边的空格. 示 ...

  10. 10.4 缓冲流 BufferedReader & BufferedWriter & 缓冲流特殊功能readLine

    缓冲流和正常流的使用大致相同,缓冲流效率更高. package day10_io_fileWrite_Read.buffer_stream; import java.io.*; /* * Buffer ...