您的位置:首页 > 其它

水管工游戏

2016-06-24 22:53 211 查看

一 题目

一块矩形土地被分为N*M的单位正方形,现在这块土地上已经埋设有一些水管,水管将从坐标为(1,1)左上角左部边缘,延伸到(N,M)右下角右部边缘。水管只有2种,如下图所示。



每种管道将占据一个单位正方形土地。你现在可以旋转这些管道,使得构成一个管道系统,即创造一条从(1,1)到(N,M)的连通管道。标有树木的方格表示这里没有管道。如下图:一个5*4的土地中(2,4)处有一个树木。



我们可以旋转其中的一些管道,使之构成一个连通的管道系统,如下图。



如果通过旋转管道可以使之构成一个连通的管道系统,就输出铺设的路径,否则输出impossible。

例如输入如下数据:

5 4

5 3 5 3

1 5 3 0

2 3 5 1

6 1 1 5

1 5 5 4

输出:

(1,1)(1,2)(2,2)(3,2)(3,3)(3,4)(4,4)(5,4)

输入的第一行为俩个整数N和M(都不超过10),接下来的N行,每行都有M个整数,表示地图中的每一小格,其中0表示树木,1~6分别表示管道的六种不同的摆放方式。

二 分析

对照上图,很容易得出摆放方式与1到6的数字之间对应的情况,如下表所示:

imagesnum

1

2

3

4

5

6

假设当前位置为 i 行 j 列,要想知道下一步往哪个方向走,除了当前的水管外,还要知道上一步的位置。

如果当前的水管是5或者6。

假如上一步为i−1行j列,那么下一步只能是i+1行j列。

通俗的说就是,从上面下来的,只能往下面去,不能往两边走。其他情况也是一样,就像过河一样只能过到对岸。

假如上一步为i+1行j列,那么下一步只能是i−1行j列。

假如上一步为i行j+1列,那么下一步只能是i行j−1列。

假如上一步为i行j−1列,那么下一步只能是i行j+1列。

如果当前的水管是1到4中的一种。

从上面下来的,和从下面上来的,可以归为同一类,都有两种情况,要么往左,要么往右。

同理,从左边和从右边过来的可以归为一类,要么往上,要么往下。

再确定返回的条件,代码就出来了,如下,如有错误,欢迎指正。

三 编码

#include <iostream>
using namespace std;

int v[100];   //保存经过点的坐标
int k = 0;
bool flag = true;    //有无路径的标志

//i和j是当前的坐标,a和b是上一步的坐标,N和M是行和列的总数
void fun(int array[10][10] , int i , int j , int a , int b , int N , int M)
{
// cout << "当前是:" << i << "  " << j << "上一步是:" << a << "  " << b << endl;

if (i == N - 1 && j == M)  //走到了右下角的右边,说明找到路径
{
flag = false;
for (int x = 0; x < k; x += 2)
{
cout << "(" << v[x] + 1 << "," << v[x + 1] + 1 << ")" << " ";
}
cout << endl;
return;
}

for (int x = 0; x < k; x += 2)  //不能回到已经走过的点,因为走过的点管道的摆放方式已确定
{
if (v[x] == i && v[x + 1] == j)
return;
}

v[k++] = i;
v[k++] = j;

if (i < 0 || j < 0 || i >= N || j >= M || array[i][j] == 0)  //如果遇到树或者出界就返回
return;

if (array[i][j] == 5 || array[i][j] == 6)
{
if (b + 1 == j)  //从左边来
{
fun(array , i , j + 1 , i , j , N , M);
}
else if (a + 1 == i)   //从上边来
{
fun(array , i + 1, j , i , j , N , M);
}
else if (b - 1 == j)   //从右边来
{
fun(array , i , j - 1 , i , j , N , M);
}
else if (a - 1 == i)   //从下边来
{
fun(array , i - 1, j , i , j , N , M);
}

}
else if(array[i][j] >= 1 && array[i][j] <= 4)
{
if (b + 1 == j || b - 1 == j)  //从左边或右边进来
{
int t = k;   //记录此时的位置,确保从当前位置分别向两个方向寻找
fun(array , i + 1 , j , i , j , N , M);
k = t;
fun(array , i - 1 , j , i , j , N , M);
}
else if (a + 1 == i || a - 1 == i)   //从上边或下边来
{
int t = k;
fun(array , i , j + 1 , i , j , N , M);
k = t;
fun(array , i , j - 1 , i , j , N , M);
}
}
}

int main()
{
int M , N;
cin >> N >> M;
int a[10][10];

for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
cin >> a[i][j];
}
}

fun(a , 0 , 0 , 0 , -1 , N , M);
if(flag)    //flag为true,说明没有找到路径
{
cout << "impossible";
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  递归