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