1. 程式人生 > 實用技巧 >AOJ 0118 Property Distribution

AOJ 0118 Property Distribution

原題目簡介

タナカ氏が HW アールの果樹園を殘して亡くなりました。果樹園は東西南北方向に H × W の區畫に分けられ、區畫ごとにリンゴ、カキ、ミカンが植えられています。タナカ氏はこんな遺言を殘していました。

果樹園は區畫単位でできるだけ多くの血縁者に分けること。ただし、ある區畫の東西南北どれかの方向に### となりあう區畫に同じ種類の果物が植えられていた場合は、區畫の境界が分からないのでそれらは 1 つ### の大きな區畫として扱うこと。

例えば次のような 3 × 10 の區畫であれば ('リ'はリンゴ、'カ'はカキ、'ミ'はミカンを表す)

同じ樹がある區畫の間の境界を消すと次のようになり、

結局 10 個の區畫、つまり 10 人で分けられることになります。

雪が降って區畫の境界が見えなくなる前に分配を終えなくてはなりません。あなたの仕事は果樹園の地図### をもとに分配する區畫の數を決めることです。

果樹園の地図を読み込み、分配を受けられる血縁者の人數を出力するプログラムを作成してください。


Input

複數のデータセットが與えられます。各データセットは空白で區切られた H, W (H, W ≤ 100) を含む### 行から始まり、続いて H × W の文字からなる H 行の文字列が與えられます。この文字列には、リンゴ### を表す '@'、カキを表す '#'、ミカンを表す '*'、の 3 文字しか現れません。

入力はゼロが2つの行で終わります。データセットの數は 20 を超えません。


Output

各データセットごとに、分配を受ける人數を1行に出力してください。


Sample Input

10 10

####*****@

@#@@@@##

@##**@@@

#***#@**

##@#@@##

@@@@@@@#

*#@@##

@@@@@##@

@#*@##**

@****#@@#@

0 0


Output for the Sample Input

33


原題目翻譯如下:

轉: 題意:在H * W的矩形果園裡有蘋果、梨、蜜柑三種果樹, 相鄰(上下左右)的同種果樹屬於同一個區域,給出果園的果樹分佈,求總共有多少個區域。 (原題的樣圖中蘋果為リ,梨為カ,蜜柑為ミ, 圖中共10個區域) 輸入:多組資料,每組資料第一行為兩個整數H、W(H <= 100, W <= 100), H =0 且 W = 0代表輸入結束。以下H行W列表示果園的果樹分佈, 蘋果是@,梨是#, 蜜柑是*。 輸出:對於每組資料,輸出其區域的個數。


思路如下:

這道題還是dfs的經典習題,但是跟以往有些不同的是:統計區域的型別有多種,因此我們需要以不同型別區域的果樹為起點,進行深度優先遍歷。最後,每統計一個型別區域的果樹(也可以理解為每進行一次dfs),我們就將其區域的個數+1。其中,統計果樹的區域可以重複,因為在原題中果樹的區域分佈不是在一起的而是分散的。具體可以見圖:

我們可以以“力”這個型別來舉例,在這張分佈圖中,“力”的分佈區域不是在一起的,是分散的。(在圖中的“力”的區域共有三片)因此,一定要注意,不能統計完一次“力”後,就不再進行統計了,因為有可能“力”的區域有多片。

所以,為了解決這個問題,我們可以利用雙重迴圈來統計圖中所有的區域,每統計完一次區域後,就將其替換成".",以免被重複遍歷到。

如若不能理解的話,請參考程式碼進行思考一下,應該就能明白什麼意思了。


程式碼如下:

#include <iostream>
#include <cstdio>
using namespace std;
char Graph[100][100];
int h, w;
int Count=0;   //代表區域的個數(初始化為0)
void dfs(int x, int y, char flag);    //代表進行深度優先搜尋的函式,其中flag代表要進行查詢的果樹型別

void dfs(int x, int y, char flag)
{
	int movex, movey;    //代表移動之後的座標
	int i, j;
	Graph[x][y] = '.';  //將搜尋完之後的果樹用.代替,免得被重複遍歷到,最終影響題目結果
	for (i = -1; i <= 1; i++)
	{
		for (j = -1; j <= 1; j++)
		{
			if (i == 0 || j == 0)   //篩選四個方向(-1,0)(1,0)(0,-1)(0,1)
			{
				movex = x + i;
				movey = y + j;
				if (movex >= 0 && movex < h && movey >= 0 && movey < w && Graph[movex][movey] == flag)
				{
					dfs(movex, movey, flag);   //繼續向下進行深度優先搜尋
				}
			}
		}
	}
}

int main()
{
	int i, j;
	char x;
	while (scanf("%d %d", &h, &w) != EOF)
	{
		if (h == 0 && w == 0)
		{
			return 0;
		}
		else
		{
			for (i = 0; i < h; i++)
			{
				for (j = 0; j < w; j++)
				{
					cin >> x;
					Graph[i][j] = x;
				}
			}
			for (i = 0; i < h; i++)
			{
				for (j = 0; j < w; j++)
				{
					if (Graph[i][j] == '@')   //查詢蘋果
					{
						dfs(i, j, '@');       //以蘋果為起點進行深度優先搜尋
						Count++;              //查詢完後,區域個數+1
					}
					else if (Graph[i][j] == '#') //查詢梨
					{
						dfs(i, j, '#');
						Count++;
					}
					else if (Graph[i][j] == '*') //查詢蜜柑
					{
						dfs(i, j, '*');
						Count++;
					}
				}
			}
			printf("%d\n", Count);    //果樹遍歷完之後輸出結果
			Count = 0;                //當一次測試例項執行完之後,我們要將區域個數清0,不然的話會影響下一次的結果

		}
	}
}