ZOJ 2412 Farm Irrigation

題目大意:

        一塊田地有若干正方形小塊組成,現在需要通過水管對該田地進行灌溉,每個小塊中都有水管,總共有如下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, 地質學的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章