您的位置:首页 > 其它

ZOJ 2412 Farm Irrigation

2014-08-01 17:35 369 查看
题目大意:

一块田地有若干正方形小块组成,现在需要通过水管对该田地进行灌溉,每个小块中都有水管,总共有如下11中水管分布方式:



题中会给出小块的分布情况,比如:

ADC

FJK

IHE

这样就代表如下分布的田地:



只有水管是无法灌溉的,必须要有水源,如上图所示,红点处就是水源,只要一个小块有水源那么和它连通的所有小块都可以接收到水,接受到水的小块都可以被灌溉,现要求出最少放几个水源可以使整个田地得到灌溉。

现有多个测例,每个测例中都给出田地的规模n×m(n行m列,1 ≤ n, m ≤ 50),接下来给一个n×m的矩阵由大写字母A ~ K组成,输入以n或m小于0表示结束,对于每个测例都输出一个最少水源数。

题目链接

注释代码:

/*
* Problem ID : ZOJ 2412 Farm Irrigation
* Author     : Lirx.t.Una
* Language   : C++
* Run Time   : 0 ms
* Run Memory : 276 KB
*/

#include <iostream>
#include <cstring>
#include <cstdio>

//田地的最大宽度
#define	MAXW	50

//这里上下左右用4位二进制数表示
//按照从高位到低位:左 上 右 下
//某一位为1就表示具有通往该方向的管子,为0就表示没有

//判断四个方向有没通管子
#define	LEFT(c)		( (c) & 8 )
#define	UP(c)		( (c) & 4 )
#define	RIGHT(c)	( (c) & 2 )
#define	DOWN(c)		( (c) & 1 )

using namespace std;

bool	ir[MAXW + 2][MAXW + 2];//irrigated,表示某个格子是否被灌溉过
char	g[MAXW + 2][MAXW + 2];//graph,表示每个格子的管道信息(二进制表示)
char	fmt[MAXW + 2];//接受临时输入的字符串

//to digit,将输入的字母转换为相应的二进制表示,比如'A' -> 1100 -> 12,就表示左右方向有管子通
char	TOD[11] = { 12, 6, 9, 3, 5, 10, 14, 13, 11, 7, 15 };//A ~ K的二进制表示形式

int		n, m;//行列数

void
dfs( int x, int y ) {

int		xx, yy;

ir[x][y] = true;//将该块灌溉

//左搜索
xx = x;//现走一步
yy = y - 1;
//yy > 0检测是否越界(超过田地范围)
//!ir[xx][yy]是否被灌溉过,如果已经被灌溉了就没有必要搜索了
//LEFT( g[x][y] ) && RIGHT( g[xx][yy] )表示如果当前左通并且下一个格子右通,则两格子相同了
if ( yy > 0 && !ir[xx][yy] && LEFT( g[x][y] ) && RIGHT( g[xx][yy] ) )
dfs( xx, yy );

//以下同理

//上搜索
xx = x - 1;
yy = y;
if ( xx > 0 && !ir[xx][yy] && UP( g[x][y] ) && DOWN( g[xx][yy] ) )
dfs( xx, yy );

//右搜索
xx = x;
yy = y + 1;
if ( yy <= m && !ir[xx][yy] && RIGHT( g[x][y] ) && LEFT( g[xx][yy] ) )
dfs( xx, yy );

//下搜索
xx = x + 1;
yy = y;
if ( xx <= n && !ir[xx][yy] && DOWN( g[x][y] ) && UP( g[xx][yy] ) )
dfs( xx, yy );
}

int
main() {

int		cnt;//水源数
int		i, j;//计数变量

while ( ~scanf("%d%d", &n, &m), n >= 0 && m >= 0 ) {

memset(ir, false, sizeof(ir));

for ( i = 1; i <= n; i++ ) {

scanf("%s", fmt + 1);
for ( j = 1; j <= m; j++ )
g[i][j] = TOD[ fmt[j] - 'A' ];
}

//把所有连通的区域用一个水源灌溉即可,这样求出来的必定是最优解
cnt = 0;
for ( i = 1; i <= n; i++ )
for ( j = 1; j <= m; j++ )
if ( !ir[i][j] ) {//只一个没灌溉过的进行灌溉,直到所有都被灌溉满

dfs( i, j );
cnt++;
}

printf("%d\n", cnt);
}

return 0;
}
无注释代码:

#include <iostream>
#include <cstring>
#include <cstdio>

#define	MAXW	50

#define	LEFT(c)		( (c) & 8 )
#define	UP(c)		( (c) & 4 )
#define	RIGHT(c)	( (c) & 2 )
#define	DOWN(c)		( (c) & 1 )

using namespace std;

bool	ir[MAXW + 2][MAXW + 2];
char	g[MAXW + 2][MAXW + 2];
char	fmt[MAXW + 2];

char	TOD[11] = { 12, 6, 9, 3, 5, 10, 14, 13, 11, 7, 15 };

int		n, m;

void
dfs( int x, int y ) {

int		xx, yy;

ir[x][y] = true;

xx = x;
yy = y - 1;
if ( yy > 0 && !ir[xx][yy] && LEFT( g[x][y] ) && RIGHT( g[xx][yy] ) )
dfs( xx, yy );

xx = x - 1;
yy = y;
if ( xx > 0 && !ir[xx][yy] && UP( g[x][y] ) && DOWN( g[xx][yy] ) )
dfs( xx, yy );

xx = x;
yy = y + 1;
if ( yy <= m && !ir[xx][yy] && RIGHT( g[x][y] ) && LEFT( g[xx][yy] ) )
dfs( xx, yy );

xx = x + 1;
yy = y;
if ( xx <= n && !ir[xx][yy] && DOWN( g[x][y] ) && UP( g[xx][yy] ) )
dfs( xx, yy );
}

int
main() {

int		cnt;
int		i, j;

while ( ~scanf("%d%d", &n, &m), n >= 0 && m >= 0 ) {

memset(ir, false, sizeof(ir));

for ( i = 1; i <= n; i++ ) {

scanf("%s", fmt + 1);
for ( j = 1; j <= m; j++ )
g[i][j] = TOD[ fmt[j] - 'A' ];
}

cnt = 0;
for ( i = 1; i <= n; i++ )
for ( j = 1; j <= m; j++ )
if ( !ir[i][j] ) {

dfs( i, j );
cnt++;
}

printf("%d\n", cnt);
}

return 0;
}

单词解释:

harvest:n, 收获

wellspring:n, 泉源,水源

pipe:n, 管子,烟斗,笛子

irrigate:vt, 灌溉

spacious:adj, 宽敞的,广阔的

colon:n, 冒号

repetition:n, 重复

pocket:n, 袋囊,容器

plot:n, 情节,图

numerous:adj, 许多的

oil deposit:n, 油田

deposit:n, 存款,沉淀物

responsible:adj, 负责的,有责任的

geologic:adj, 地质学的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: