杂谈:编程解决水管工游戏
来源:互联网 发布:2016淘宝个性化刷法 编辑:程序博客网 时间:2024/04/29 18:38
杂谈:编程解决水管工问题
程序设计是一门极难上手的技能,仅仅凭着课堂上的知识,只能是熟悉一门编程语言的语法。但要是用计算机来解决一些实际的问题,哪怕是智力问题,课本上的知识是远远不够的。
编程就像学游泳。学游泳一定要在水里学,要在水里摸索体会。学编程也是如此。
下面给大家带来一个有趣的小问题,希望大家能够学习到其中的程序设计思维与方法,尤其是中间建立模型的过程,相当精彩,大家欣赏一下。
以下内容改编自《啊哈,算法》第4章第6节
问题描述:
一块矩形土地被分为N*M的单位正方形,这块土地里埋设一些水管,水管将从坐标为(1,1)的矩形土地的左上角左部边缘,延伸到坐标为(N,M)的矩形土地的右下角右部边缘。
水管只有两种:
- 弯曲水管:L
- 直水管: ━
土地中还有障碍物(比如树木等)
每种水管占据一个单位正方形土地。可以旋转这些管道,使其构成一个管道系统,创造一条从(1,1)到(N,M)的连通
管道。有障碍物的方格里没有管道。
建模开始:
我们用数字0表示障碍物,1到6表示管道的六种不同的摆放方式(如下表)。
于是,程序的输入可以规定为:
第一行输入矩形土地的大小n,m。
接下来输入n行m列的数字,表示每个单位正方形土地中的管道情况(数字0表示障碍物,1到6表示管道)
样例输入为:
5 4
5 3 5 3
1 5 3 0
2 3 5 1
6 1 1 5
1 5 5 4
(自行脑补实际管道铺设情况)
程序要输出的是应该是铺设的路径,如果不存在这样的路径,则输出impossible。
样例输出:
The path is:
(1,1) (1,2) (2,2) (3,2) (3,3) (3,4) (4,4) (5,4)
(注:铺设管道的最左上角起点坐标为(1,1),最右下角终点坐标为(5,4),规定进水口在最左上角方格的左边,出水口在最右下角方格的右边,输出路径可能不唯一)
编程思路:
以下分析过程中的水管的图形与土地的状态请自行脑补
因为只有两种水管,直管(2种状态)和弯管(4种状态)。首先从(1,1) 开始尝试。(1,1)是直管,进水口又在
(1,1)的左边,因此(1,1)处的水管只能用5号摆放方式。
之后达到(1,2)。(1,2)处是弯管,进水口在(1,2)的左边,因此(1,2)有两种排放方式,分别是3号与4号。由于4号
摆放方式会出界,只能用3号摆放方式,从而来到了(2,2)。
(2,2)处是直管,进水口在上方,只能用6号摆放方式,接下来,来到(3,2)。
(3,2)是弯管,进水口在上面,有2种摆放方式可以选择,分别是1号和4号。
这两种选择都可以,我们就要分别去尝试……
依次类推,直到来到(n,m+1)为止,方案产生。
代码实现
这里用到了深度优先搜索DFS。当处在(x,y)处时,依次枚举当前管道的每一张摆放方式,但并非每一种都可以,还要
判断(x,y)处的进水口的方向。
这里规定进水口在左边用数字1表示,在上边用2表示,右边用3表示,下边用4表示。
要输出路径,只需要用一个栈存放相应的结点就可以了。
#include <stdio.h>#define MAX_N 55#define MAX_M 55int a[MAX_N][MAX_M], book[MAX_N][MAX_M];int n, m, flag = 0;struct node { int x; int y;}s[100];int top = 0;void dfs(int x, int y, int front) //x,y表示当前处理的位置坐标,front表示(x,y)进水口的方法{ int i; //判断是否达到终点 if (x == n && y == m + 1) { flag = 1; //找到铺设方案 printf("The path is:\n"); for (i = 1; i <= top; i++) printf("(%d, %d) ", s[i].x, s[i].y); printf("\n"); return; } //判断是否越界 if (x < 1 || x > n || y < 1 || y > m) return; //判断(x,y)处是否已经遍历过 if (book[x][y] == 1) return; ++top; s[top].x = x; s[top].y = y; //将当前坐标压栈 //当前水管是直管的情况 if (a[x][y] >= 5 && a[x][y] <= 6) { if (front == 1) dfs(x, y+1, 1); //进水口在左边,只能用5号摆放方式 if (front == 2) dfs(x+1, y, 2); //进水口在上边,只能用6号摆放方式 if (front == 3) dfs(x, y-1, 3); //进水口在右边,只能用5号摆放方式 if (front == 4) dfs(x-1, y, 4); //进水口在下边,只能用6号摆放方式 } //当前水管是弯管的情况 if (a[x][y] >= 1 && a[x][y] <= 4) { //进水口在左边 if (front == 1) { dfs(x+1, y, 2); dfs(x-1, y, 4); } //进水口在上边 if (front == 2) { dfs(x, y+1, 1); dfs(x, y-1, 3); } //进水口在右边 if (front == 3) { dfs(x-1, y, 4); dfs(x+1, y, 2); } //进水口在下边 if (front == 4) { dfs(x, y+1, 1); dfs(x, y-1, 3); } } book[x][y] = 0; //取消标记 top--; //将当前坐标从栈中弹出 return;}int main(void){ int i, j, num = 0; while (scanf("%d %d", &n, &m) == 2) { for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) scanf("%d", &a[i][j]); dfs(1, 1, 1); if (flag == 0) printf("impossible\n"); } return 0;}
总结
学习编程的过程其实是一种修炼,不断挑战难题,挑战自己,才能不断提升自己的思维能力,锻炼自己的数理能力,
丰富自己的代码能力和编程技巧。
这里的水管工问题就是很有启发性的例子。还有许多有趣的问题值得我们用计算机编程去解决,这样我们可以从算法思维的角度考察问题,获得灵感。
这样的问题有很多,推荐大家一本书《算法趣题》,里面收录了很多有趣的问题,值得我们思考,并且在计算机上用代码实现。
- 杂谈:编程解决水管工游戏
- 水管工游戏
- 水管工游戏
- 4.6水管工游戏
- 水管工游戏
- 水管工游戏--dfs的应用
- 水管工游戏(随机地图版)
- 水管道游戏
- 啊哈算法DFS应用之水管工游戏
- tianchai 12023 水管工游戏(DFS搜索)
- 水管工和教授
- 数学教授水管工
- 水管工和教授
- 游戏杂谈
- 游戏杂谈
- FZU-1892(bfs)接水管游戏
- 一个水管工的故事
- 编程杂谈
- 淡粉色的花期
- UVA P489 Hangman Judge
- Maven JavaWeb工程初探
- ajax验证修改密码
- Express模版快速搭建
- 杂谈:编程解决水管工游戏
- Unity内建的着色器
- 3. Longest Substring Without Repeating Characters
- 使用socket.io做一个简单的WEB聊天室
- C语言:动态顺序表的增删查改,数据结构
- <电路小常识>USB接口定义
- [模板] 差分约束系统
- 手机号码归属地查询工具的正确使用方法
- HDU 1166 敌兵布阵 树状数组