城堡問題(DFS)

 城堡問題(搜索) 
總時間限制: 1000ms 內存限制: 65536kB

描述 
這裏寫圖片描述
(圖 1)

# = Wall 
| = No wall 
- = No wall

圖1是一個城堡的地形圖。請你編寫一個程序,計算城堡一共有多少房間,最大的房間有多大。城堡被分割成m*n(m≤50,n≤50)個方塊,每個方塊可以有0~4面牆。

輸入 
程序從標準輸入設備讀入數據。第一行是兩個整數,分別是南北向、東西向的方塊數。在接下來的輸入行裏,每個方塊用一個數字(0≤p≤50)描述。用一個數字表示方塊周圍的牆,1表示西牆,2表示北牆,4表示東牆,8表示南牆。每個方塊用代表其周圍牆的數字之和表示。城堡的內牆被計算兩次,方塊(1,1)的南牆同時也是方塊(2,1)的北牆。輸入的數據保證城堡至少有兩個房間。

輸出 
城堡的房間數、城堡中最大房間所包括的方塊數。結果顯示在標準輸出設備上。

樣例輸入 


11 6 11 6 3 10 6 
7 9 6 13 5 15 5 
1 10 12 7 13 7 5 
13 11 10 8 10 12 13

樣例輸出 

9

例:11的二進制爲1011,每一位二進制分別表示“南牆”“東牆”“北牆”“西牆”,爲1表示有牆,爲0表示沒牆。
按位與運算符&的使用:如:11&4 <=> 1011 & 0100 = 0000 = 0。相同爲1,不同爲0。
豎式:1011
        &0100
           -----
           0000

解題思路:
對每個方塊,深度優先搜索(DFS),從而給這個方塊能夠達到的所有位置染色。最後統計出一共有多少種顏色,以及每種顏色的數量。
比如:
1 1 2 2 3 3 3
1 1 1 2 3 4 3
1 1 1 5 3 5 3
1 5 5 5 5 5 3
從而一共有5個房間,最大的房間(1)佔據9個格子。

【解法一:遞歸】

//AC
#include<iostream>
#include<stack>
#include<cstring>
using namespace std;
int R,C;    //行列數
int rooms[60][60];
int color[60][60];  //房間是否染色過的標記
int maxRoomArea=0,roomNum=0;
int roomArea;
//用遞歸解決:
void Dfs(int i,int k)
{
    if (color[i][k])
        return ;
    ++roomArea;
    color[i][k]=roomNum;
    if ((rooms[i][k]&1)==0)	
        Dfs(i,k-1); 	//向左走
    if ((rooms[i][k]&2)==0)
        Dfs(i-1,k); 	//向上走
    if ((rooms[i][k]&4)==0)
        Dfs(i,k+1); 	//向右走
    if ((rooms[i][k]&8)==0)
        Dfs(i+1,k); 	//向下走
}
int main()
{
    cin>>R>>C;
    for (int i=1;i<=R;i++)
        for (int k=1;k<=C;k++)
            cin>>rooms[i][k];
    memset(color,0,sizeof(color));
    for (int i=1;i<=R;i++)
    {
        for (int k=1;k<=C;k++)
        {
            if (!color[i][k])
            {
                ++roomNum;
                roomArea=0;
                Dfs(i,k);
                maxRoomArea=max(roomArea,maxRoomArea);
            }
        }
    }
    cout<<roomNum<<endl;
    cout<<maxRoomArea<<endl;
    return 0;
}
【解法二:堆棧】

/*這是一種仿照BFS模板的一種寫法,O(∩_∩)O哈哈~,現在我終於明白BFS和DFS(堆棧解法)的區別了,其實套用BFS的模板一樣可以實現DFS,說白了用堆棧寫的DFS和用隊列寫的BFS只有一點不同,那就是它們所用的數據結構不同,就是因爲這兩種不同的數據結構的不同特性,才使得深搜和廣搜效果不同。******堆棧爲後進先出,這使得每次遍歷時第一次也和廣搜一樣讀入的第一步能走的節點,接下來會以棧頂元素爲起點向下搜從該點一步能到的節點,但是每次查詢的一個元素都是此次遍歷的最後一個元素,也就是第二次查詢的都是起點能到的下一層元素。******隊列爲先進先出,每次遍歷時第一次也一樣讀入的第一步能走的節點,接下來會以隊首元素爲起點向下搜從該點一步能到的節點,但是每次查詢時都是先查詢一個元素都是上一層得元素,直到該層結束,在查下一層,因爲上一層元素總是先入隊的*/

//AC
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;

int mark[60][60];
int room[60][60];
int n,m,num=0,area,maxarea;
struct data
{
    int x,y;
};

void dfs(int x,int y)
{
    stack<data> stk;
    data p,pp;
    p.x=x;
    p.y=y;
    stk.push(p);
    while (!stk.empty())
    {
        p=stk.top();
        if (mark[p.x][p.y])
            stk.pop();
        else
        {
            ++area;
            mark[p.x][p.y]=1;
            if ((room[p.x][p.y]&1)==0&&p.y>0&&!mark[p.x][p.y-1])
            {
                pp.x=p.x;
                pp.y=p.y-1;
                stk.push(pp);
            }
            if ((room[p.x][p.y]&2)==0&&p.x>0&&!mark[p.x-1][p.y])
            {
                pp.x=p.x-1;
                pp.y=p.y;
                stk.push(pp);
            }
            if ((room[p.x][p.y]&4)==0&&p.y+1<n&&!mark[p.x][p.y+1])
            {
                pp.x=p.x;
                pp.y=p.y+1;
                stk.push(pp);
            }
            if ((room[p.x][p.y]&8)==0&&p.x+1<m&&!mark[p.x+1][p.y])
            {
                pp.x=p.x+1;
                pp.y=p.y;
                stk.push(pp);
            }
        }
    }
}
int main()
{
    while (scanf("%d%d",&m,&n)!=EOF)
    {
        maxarea=0;
        memset(mark,0,sizeof(mark));
        for (int i=0; i<m; i++)
            for (int j=0; j<n; j++)
                scanf("%d",&room[i][j]);
        for (int i=0; i<m; i++)
        {
            for (int j=0; j<n; j++)
            {
                if (!mark[i][j])
                {
                    area=0;
                    ++num;
                    dfs(i,j);
                    if (area>maxarea)
                        maxarea=area;
                }
            }
        }
        printf("%d\n%d\n",num,maxarea);
    }
    return 0;
}

【解法三:其實這也是用堆棧解決的,只是裏面用的結構體內的構造函數,而不是兩個結構體變量】

#include <iostream>
#include <stack>

using namespace std;

int m, n, roomNum = 0, curRoomAera;
int map[50][50], color[50][50] = {0};

struct Room
{
    int x, y;
    Room(int x, int y):x(x),y(y) {}
};
//用棧解決:
void dfs(int X, int Y)
{
    stack<Room> stk;
    stk.push(Room(X, Y));
    int x, y;
    while (!stk.empty())
    {
        Room topRoom = stk.top();
        x = topRoom.x;
        y = topRoom.y;
        if (color[x][y])
            stk.pop();
        else
        {
            curRoomAera++;
            color[x][y] = roomNum;	//標記棧頂元素
	    //坑爹啊......&(按位與)運算符的優先級小於 == ,所以必須加括號
            if (((map[x][y] & 1) == 0) && (y > 0) && !color[x][y-1])	//千萬注意!&1==0時對應的一定是y-1,即必須向左走
                stk.push(Room(x, y-1));    
            if (((map[x][y] & 2) == 0) && (x > 0) && !color[x-1][y])	//千萬注意!&2==0時對應的一定是x-1,即必須向上走	
                stk.push(Room(x-1, y));  
            if (((map[x][y] & 4) == 0) && (y+1 < n) && !color[x][y+1])	//千萬注意!&4==0時對應的一定是y+1,即必須向右走
                stk.push(Room(x, y+1));
            if (((map[x][y] & 8) == 0) && (x+1 < m) && !color[x+1][y])	//千萬注意!&8==0時對應的一定是x+1,即必須向下走
                stk.push(Room(x+1, y));
        }
    }
}

int main()
{
    int maxRoomAero = 0;
    cin >> m >> n;
    for( int i = 0; i < m; i++)
        for (int j = 0; j < n; j++)
            cin >> map[i][j];
    for( int i = 0; i < m; i++)
        for (int j = 0; j < n; j++)
            if (!color[i][j])
            {
                roomNum++;
                curRoomAera = 0;
                dfs(i, j);
                if (curRoomAera > maxRoomAero)
                    maxRoomAero = curRoomAera;
            }
    cout << roomNum << endl << maxRoomAero <<endl;
}



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