dfs深度優先算法


題目:

今天是陰歷七月初五,acm隊員zb的生日。zb正在和C小加、never在武漢集訓。他想給這兩位兄弟買點什么慶祝生日,經過調查,zb發現C小加和 never都很喜歡吃西瓜,而且一吃就是一堆的那種,zb立刻下定決心買了一堆西瓜。當他准備把西瓜送給C小加和never的時候,遇到了一個難 題,never和C小加不在一塊住,只能把西瓜分成兩堆給他們,為了對每個人都公平,他想讓兩堆的重量之差最小。每個西瓜的重量已知,你能幫幫他么?

輸入:

多組測試數據(<=1500)。數據以EOF結尾
第一行輸入西瓜數量N (1 ≤ N ≤ 20)
第二行有N個數,W1, …, Wn (1 ≤ Wi ≤ 10000)分別代表每個西瓜的重量

輸出:

輸出分成兩堆后的質量差

樣例輸入:

5

5 8 13 27 14

樣例輸出:

3

 

下面是源程序:

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<fstream>


using namespace std;

int melon[21];
int n;
int mins;//不要定義為min或max,以免與庫函數沖突
int total;

void findmin(int i,int sum)//i為層數;sum為當前和
{    
    if(i==n) //到i = n;時,最后一次討論是否包含[n-1];
    {
        int temp=abs(total - sum - sum);//當前兩部分的差額    
        if(mins > temp)
            mins=temp;
        return;
    }
/*  這里是一個剪枝;不用所有的都走到底部。
    if(sum > total/2 )//如果當前的和已經大於一半,剪枝
    {
        int temp=abs(total - sum - sum);//當前兩部分的差額    
        if(mins > temp)//如果最小差額比當前的差額大
        {
            mins = temp;            
        }
        return ;
    }
*/
    findmin(i+1,sum);//不算melon[i]
    findmin(i+1,sum+melon[i]);//算上melon[i]
}

int main()
{
    int i;    

    while(cin>>n)
    {    
        total=0;
        mins=9999999;
        for(i=0;i<n;i++)
        {
            scanf("%d",&melon[i]);
            total+=melon[i];//西瓜總重量
        }//for
        if(n==0)
            cout<<melon[0]<<endl;
        else
        {
            findmin(0,0);
            cout<<mins<<endl;
        }
    }//while
    return 0;
}

 深度優先,就是從一個點出發,一直深入下去,直到葉子節點,然后返回,在深入,直到

遍歷完所有的節點,為了深刻的理解遍歷的過程,可以單步跟蹤一下。

單步跟蹤:遇到函數按F11,進入函數;進入函數后按F10,單步走。這樣就可以清楚的查看每一步。

下面就是跟從得到的樹狀圖:

注釋:輸入的數據是:   2      1     2

就是從兩個,分別是1和2     [0]代表第0個,[1]代表第1個。

遍歷時就會把所有的情況都遍歷一遍,每個元素都可能在或不在集合中。

 

 

 

問題2  素數環

有一個整數n,把從1到n的數字無重復的排列成環,且使每相鄰兩個數(包括首尾)的和都為素數,稱為素數環。

為了簡便起見,我們規定每個素數環都從1開始。例如,下圖就是6的一個素數環。

輸入:

有多組測試數據,每組輸入一個n(0<n<20),n=0表示輸入結束

輸出:

每組第一行輸出對應的Case序號,從1開始。
如果存在滿足題意敘述的素數環,從小到大輸出。
否則輸出No Answer。

樣例輸入:

6

8

3

0

樣例輸出:

分析:

(1)如果n為奇數,那么必然有兩個奇數相鄰,他們的和為偶數,不是素數。

(2)一邊排列一邊檢查,提前剪枝。

(3)遞歸思想:如果要求一個數組,或者是否包含某些元素,都是在main{}中調用時

令層數t=0,傳遞,然后在遞歸函數中增加t,如f(t+1);這樣就深入了。

還要有判斷條件一般都是t==n時,判斷是不是滿足某些條件,然后再返回。

當然,剪枝就是提前返回,就是t沒有到n時就返回了。

下面是源代碼:

#include<iostream>
#include<stdio.h>

using namespace std;

//直接通過一個數對應的索引號查看是不是素數
bool IsPrime[]={
        0, 0, 1, 1, 0, 1, 0,
        1, 0, 0, 0, 1, 0, 1,
        0, 0, 0, 1, 0, 1, 0,
        0, 0, 1, 0, 0, 0, 0,
        0, 1, 0, 1, 0, 0, 0,
        0, 0, 1
};//因為n<20;最大素數和為19+18=37;
void Output(int a[],int n)
{
    int i;
    cout<<"1";
    for(i = 1 ; i < n ; i++ )
    {
        cout << " "<<a[i];            
    }
    cout<<endl;
}

bool IsOk(int a[],int lastindex,int cur)//判斷當前序列是不是合法
{
    if(lastindex < 0)  //!!!!!!!!!關鍵,0 號沒有前驅,千萬不要寫成lastindex < 1
        return true;
    if(!IsPrime[cur+a[lastindex]]) //加入時與前一個元素的和不是素數
        return false;
    for(int i = 0;i <= lastindex; ++i)//判斷這個數字是不是被用過了
    {
        if(cur == a[i])
            return false;
    }
    return true;
}

void PrimeCircle(int a[],int n,int t)//判斷是不是素數環,t為層數
{
    if(n == 1)
    {
        cout<<"1"<<endl;
        return;
    }
    if((n & 1) ==1 )//奇數沒有素數環
        return;
    if(n == t)//結束條件一般都是t==n, 因為遞歸時用到t+1,傳到下層為n=t+1;
          //所以t=[n-1]是末尾
    {
        if(IsPrime[a[0] + a[n-1]])  //判斷首尾
            Output(a,n);
        return;
    }
    for(int i = 1;i <= n; ++i) //判斷1 到 n 是否滿足條件
    {
        a[t] = i;//
        if(IsOk(a, t-1, i)) //判斷新加入的值是不是滿足條件
            PrimeCircle(a, n ,t+1);//深入
    }
}
int main()
{
    int n;
    int cnt=0;

    while(++cnt)
    {
        scanf("%d",&n);
        if(n == 0)
        {
            break;
        }
        
        int ans[20]={1};

        printf("Case %d:\n",cnt);
        //因為要多次返回,所以不能這么判斷bool flag=PrimeCircle(ans,n,1);
//一般都是從t=0層開始,這里第一個數已經定為1

        if( n % 2 == 0 || n ==1 )
            PrimeCircle(ans,n,1);
        else
            printf("No Answer\n");    
    }
    
    return 0;
}

 注:http://www.cnblogs.com/graphics/archive/2010/03/27/1698403.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM