經典搜索_Poj_1011

/*
題目大意是將零碎的木棒小片湊成長度相同的木棒,要求木棒長度最短
*/


//以下的代碼是網上一哥們那看到的,因爲很短所以很喜歡
//我加了註釋,並做了一個簡單的剪枝(在重複長度比較多的情況下,時間省了不是一點的問題哦!)
#include <cstdio>  
#include <algorithm>  
#include <functional>  
using namespace std;  
  
const int maxN = 64 + 5;  
int n, stick[maxN], len, m;  //依次爲:輸入個數,小木棒塊,當前木棒最終長度,大木棒數目
bool used[maxN] = {false}, done;  //依次爲:記錄第x個小木棒是否已經使用過,搜索是否完成
  
void dfs(int k, int now, int cnt) //依次爲:爲匹配當前木棒所搜索的進度,當前木棒長度,當前已經匹配好的木棒數目
{  
    if (cnt == m)  //m根木棒全部匹配完畢,done記錄爲true
        done = true;  
    else if (now == len)  //當前木棒已經匹配完畢,搜索並匹配下一根木棒
        dfs(0, 0, cnt + 1);  
    else {    
int pre=-1;
        for (int i = k; i < n; ++i)  
            if (!used[i] && stick[i] != pre && now + stick[i] <= len) //同一個決策環境下,選擇兩個同樣長的木棒是沒有必要的 
            {  
//假設當前匹配木棒過程中
                used[i] = true;  
                pre = stick[i]; 
                dfs(i + 1, now + stick[i], cnt);  //將k改爲i,在原基礎上進行部分剪枝(匹配當前木棒時,已經捨棄的木棒,在以後肯定也不會用上)
                used[i] = false;  
                if (k == 0 || done)  
                    return;  
            }  
    }  
}  
  
  
int main()  
{  
    while (scanf("%d", &n), n > 0)  
    {  
        int sum = 0;  
        for (int i = 0; i < n; ++i)  
        {  
            scanf("%d", &stick[i]);  
            sum += stick[i];  
        }  
//排序
        sort(stick, stick + n, greater<int>());  
        done = false;  
//順序搜索所有可能性的長度
        for (len = stick[0]; len <= sum; ++len)  
            if (sum % len == 0)  //只有整出纔有可能性,然後DFS;
            {  
                m = sum / len;  
                dfs(0, 0, 0);  
                if (done)//成功就break;
                    break;
            }
        printf("%d\n", len);  
    }  
    return 0;  
}









#include<iostream>
using namespace std;


int n;//輸入的個數
int num[64];//存儲小木棒塊
bool sign[64];//用來記錄該點是否訪問過
int sum;//存儲總長度
int stick_num,stick_lenth;//存儲當前假設的大木棒數、大木棒長度
bool all_ok;


void dfs(int num_i,int now_lenth,int now_num)//num_i:從數組的num_i開始搜索;now_lenth:當前匹配的木棒的長度;now_num:當前已經匹配完畢的木棒的數量
{
if(now_num==stick_num)//搜索完畢
all_ok=true;
else if(now_lenth==stick_lenth)//當前木棒匹配完成
dfs(0,0,now_num+1);
else
{
int pre = -1;
int i;//輔助變量
for(i=num_i;i<n;i++)
{
if(!sign[i] && num[i]!=pre && now_lenth+num[i]<=stick_lenth)
{
sign[i]=true;
dfs(i+1,now_lenth+num[i],now_num);
sign[i]=false;
pre = num[i];//記錄前驅,防止當前環境下選取同一個長度的小木棒
if(num_i==0 || all_ok) return;//如果是第一根,那麼必定選取,無需考慮當前環境。如果已經完成,也停止。
}
}
}
}




int main()
{
while(cin>>n,n>0)
{
all_ok=false;//標記搜索是否完成
sum=0;
int i,j;//輔助變量
//數據初始化
for(i=0;i<n;i++)
{
cin>>num[i];
sum+=num[i];
}
memset(sign,0,sizeof(sign));
//排序,他的目的之一是剪枝,因爲當前要了某一種長度的小木棒後,相同的就全部忽視了
int max_num,max_i,ex;
for(i=0;i<n-1;i++)
{
max_i=i;
max_num=num[i];
for(j=i+1;j<n;j++)
{
if(max_num<num[j])
{
max_i=j;
max_num=num[j];
}
}
if(max_i!=i)
{
ex=num[i];
num[i]=num[max_i];
num[max_i]=ex;
}
}
//DFS
for(stick_lenth=num[0];stick_lenth<=sum;stick_lenth++)
{
if(sum%stick_lenth) continue;//如果不能整除則長度繼續增加(木棒根數必須是整數)
stick_num=sum/stick_lenth;
dfs(0,0,0);//深搜
if(all_ok) break;
}
printf("%d\n",stick_lenth);
}
return 0;
}

發佈了29 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章