水管工游戏
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的数字之间对应的情况,如下表所示:images | num |
---|---|
1 | |
2 | |
3 | |
4 | |
5 | |
6 |
如果当前的水管是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; }
相关文章推荐
- C#递归算法之分而治之策略
- 有关数据库SQL递归查询在不同数据库中的实现方法
- C#中的递归APS和CPS模式详解
- WinForm实现按名称递归查找控件的方法
- C#递归方法实现无限级分类显示效果实例
- 使用SqlServer CTE递归查询处理树、图和层次结构
- C#递归算法之打靶算法分析
- C#中的尾递归与Continuation详解
- C#递归实现显示文件夹及所有文件并计算其大小的方法
- php递归创建目录的方法
- PHP递归创建多级目录
- Javascript递归打印Document层次关系实例分析
- C#递归算法寻找数组中第K大的数
- C++使用递归方法求n阶勒让德多项式完整实例
- C#用递归算法解决经典背包问题
- oracle 使用递归的性能提示测试对比
- 使用curl递归下载软件脚本分享
- Perl脚本实现递归遍历目录下的文件
- JavaScript的递归之递归与循环示例介绍
- C# 递归查找树状目录实现方法