基礎DFS(poj 1321,hdoj 2553,hdoj 5113)

小白今天也學習了一道dfs的題,想記錄下來,嘿嘿嘿

poj 1321

棋盤問題
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 85425 Accepted: 39462

Description

在一個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請編程求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案C。

Input

輸入含有多組測試數據。
每組數據的第一行是兩個正整數,n k,用一個空格隔開,表示了將在一個n*n的矩陣內描述棋盤,以及擺放棋子的數目。 n <= 8 , k <= n
當爲-1 -1時表示輸入結束。
隨後的n行描述了棋盤的形狀:每行有n個字符,其中 # 表示棋盤區域, . 表示空白區域(數據保證不出現多餘的空白行或者空白列)。

Output

對於每一組數據,給出一行輸出,輸出擺放的方案數目C (數據保證C<2^31)。

Sample Input

2 1
#.
.#
4 4
…#
…#.
.#…
#…
-1 -1

Sample Output

2
1

小白剛剛接觸DFS,還不是很理解這個東西,感覺一層一層遞歸好神奇 ,還是需要多理解,多練習啊!DFS的代碼比BFS短,但是不容易理解,還是得多做題,恩。

#include <iostream>
#include <string.h>
using namespace std;
char maps[9][9];//讀取棋盤
int lie[9],ans=0,k,n,m=0;
void dfs(int row)
{
    if(row>n)//超出棋盤範圍則返回
        return;
    if(m==k)//當搜索長度與要求的相同時,返回
    {
        ans++;
        return;
    }
    for(int i=0;i<n;i++)
    {
        if(maps[row][i]=='#'&&lie[i]==0)
        {
            lie[i]=1;
            m++;
            dfs(row+1);
            m--;//恢復之前的狀態
            lie[i]=0;
        }
    }
    dfs(row+1);//下一行
}
int main()
{
    while(cin>>n>>k&&n!=-1)
    {
        ans=0;m=0;
        memset(maps,0,sizeof(maps));
        memset(lie,0,sizeof(lie));
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
                cin>>maps[i][j];
        }
        dfs(0);
        cout<<ans<<endl;
    }
}

恢復狀態那裏需要多加理解,它是遞歸返回之後接着找該層合適的點,那麼下一層自然要恢復成沒有被訪問過的狀態。

hdoj 2553 N皇后問題

題目大意: 此題是比較簡單的N皇后問題,即在10以內的N皇后問題,在棋盤上放置n個皇后,使他們不同行,不同列,不同對角線,詢問有多少個放置方法。

題解: 此題需要用到dfs搜索,重要的是 回溯與剪枝 ,即去除不符合要求的放置方法。首先要打表,如果不打表會超時,然後運用dfs搜索,然後check函數判斷是否符合要求,這裏放在不同對角線,從(i,j)向斜對角走a步,新座標(r,c)有四種情況:(i-a,j-a),(i-a,j+a),(i+a,j-a),(i+a,j+a)。總結起來就是,|i-r|=|j-c|

AC代碼:

#include <iostream>
#include <string.h>
#include <cmath>
using namespace std;
int col[12]={0};
int ans[12]={0};
int n,sum=0;
bool check(int c,int r)
{
    for(int i=0;i<r;i++)//從每一排檢查該列有沒有已經放下的
    {
        if(col[i]==c||abs(col[i]-c)==abs(i-r))
            return false;
    }
    return true;
}
void dfs(int r)
{
    if(r==n)
    {
        sum++;
        return;
    }
    for(int i=0;i<n;i++)//每一列
    {
        if(check(i,r))
        {
            col[r]=i;
            dfs(r+1);
        }
    }
}
int main()
{
    for(n=0;n<=10;n++)//先打表
    {
        memset(col,0,sizeof(col));
        sum=0;
        dfs(0);//從第0排開始搜索
        ans[n]=sum;
    }
    while(cin>>n&&n)
    {
        cout<<ans[n]<<endl;
    }
}

hdoj 5113 Black And White
(此題大部分是自己寫的emm,但是在剪枝的時候看的dalao的代碼)

題目大意: 塗顏色問題,相鄰兩塊區域顏色不能相同(即共享某一條邊的區域),並且每種顏色指定出現次數,且各種顏色出現次數相加之和爲總塊數。寫出一個符合題意的塗色方法。

題解: 畢竟第一次自己寫dfs,中間出現了很多小錯誤。這裏建議在寫maps數組時,下標從1開始,在判斷是否可以在這個區域放某種顏色時比較方便。整體思路就是用dfs搜索,從(1,1)開始,然後依次往下,先判斷再塗顏色,如果此方案不可行,則遞歸會回退。如果搜索到最後此方案可行,則需要再在回退時加上return 1。
在剪枝時,如果剩下塊數的一般小於某種顏色剩下的顏色數,則此方案一定不可行(看的dalao的代碼,據說自己畫畫就出來了)。

AC代碼:

#include <iostream>
#include <string.h>
using namespace std;
int maps[6][6];
int num[26];
int tmp[26];
int n,m,k;
int dfs(int r,int c)
{
    int flag=0;
    if(r==n+1)
    {
        return 1;
    }
    int sum=(n*m-(r-1)*m-c+2)/2; //剪枝
    for(int i=1;i<=k;i++)
    {
        if(num[i]-tmp[i]>sum)
            return 0;
    }
    for(int i=1;i<=k;i++)
    {
        if(tmp[i]>=num[i]||maps[r][c-1]==i||maps[r-1][c]==i)
            continue;
        maps[r][c]=i;
        tmp[i]++;
        if(c==m)
            flag=dfs(r+1,1);
        else
            flag=dfs(r,c+1);
        if(flag==1)//回退時,如果方案可行,則需要返回1
            return 1;
        tmp[i]--; //不要忘記回到之前的狀態
        maps[r][c]=0;
    }
    return 0;
}
int main()
{
    int w,t=0;
    cin>>w;
    while(w--)
    {
        memset(maps,0,sizeof(maps));
        memset(tmp,0,sizeof(tmp));
        t++;
        cin>>n>>m>>k;
        for(int i=1;i<=k;i++)
        {
            cin>>num[i];
        }
        cout<<"Case #"<<t<<":"<<endl;
        int flag=dfs(1,1);
        if(flag==0)
            cout<<"NO"<<endl;
        else
        {
            cout<<"YES"<<endl;
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=m;j++)
                {
                    cout<<maps[i][j];
                    if(j==m)
                        cout<<endl;
                    else
                        cout<<" ";
                }
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章