POJ 1011 Sticks

題目大意:給你n及n個小棍的長度,讓你求出一個最小長度len,使n個小棒能無重複且無遺漏的拼接成若干根長度爲len的木棒。

思路:對可行長度進行枚舉,通過DFS判斷該長度是否可行。由於要求最小可行解,所以從小到大枚舉。

對於這裏的DFS,有許多可以剪枝和優化的地方,值得學習:

(1)將棒的長度從大到小排列。事實上,如果按小棍長度從大到小進行測試,如果某長度恰好能填滿可行解len,那麼如果使用更長的小棍,長度顯然會超過len,顯然不行。如果使用更短的小棍,即使存在某個也能填滿len的方案,該方案也不比使用長小棍更有可能獲得可行解。

(2)令小棍總長度sum_len,當前枚舉長度爲test_len,如果sum_len mod test_len != 0,則剪枝。

(3)如果已經找到一個可行解,則對以後的所有情況剪枝。

(4)在填充len時,如果前一個小棍沒有用過且當前小棍與前一個小棍長度相等,則剪枝。這裏是防止重複測試。

(5)如果第一根小棍不能拼接成len,則剪枝。這個剪枝威力巨大。。我從TLE直接AC了。

事實上可能還有別的剪枝,因爲我的程序運行了16MS,還沒有到0MS秒殺的地步。而且我的程序對某些變態數據也有心無力。

變態數據:

64
40 40 30 35 35 26 15 40 40 40 40 40 40 40 40 40 40 40 40 40 40

40 40 43 42 42 41 10 4 40 40 40 40 40 40 40 40 40 40 40 40 40

40 25 39 46 40 10 4 40 40 37 18 17 16 15 40 40 40 40 40 40 40

40

答案爲:454。

運行時間:5.5s+

 

#include <iostream>
#include <algorithm>

using namespace std;

struct Stick
{
    int len;
    bool have_used;
}stick[80];

int num,sum_len,max_len,piece_num,piece_len;
bool flag;

bool compare(struct Stick a,struct Stick b)
{
    return a.len>b.len;
}

void dfs(int pos,int len_now)
{
    int i;
    if (flag)
        return ;
    if (piece_num==0)
    {
        flag=true;
        return ;
    }
    if (len_now==piece_len)
    {
        piece_num--;
        dfs(0,0);
        piece_num++;
        return ;
    }
    for (i=pos;i<num;i++)
    {
        if (flag)
            return ;
        if (len_now+stick[i].len>piece_len)
            continue;
        if (stick[i].have_used)
            continue;
        if (i>0 && stick[i-1].have_used==false && stick[i].len==stick[i-1].len)
            continue;
        stick[i].have_used=true;
        dfs(i+1,len_now+stick[i].len);
        stick[i].have_used=false;
        if (pos==0)
            return ;
    }
}

int main()
{
    int i;
    while (scanf("%d",&num)==1 && num!=0)
    {
        for (i=0,sum_len=0,max_len=-1;i<num;i++)
        {
            scanf("%d",&stick[i].len);
            stick[i].have_used=false;
            sum_len+=stick[i].len;
        }
        sort(stick,stick+num,compare);
        max_len=stick[0].len;
        for (i=max_len,flag=false;i<=sum_len && flag==false;i++)
        {
            if (sum_len%i!=0)
                continue;
            piece_len=i;
            piece_num=sum_len/i;
            dfs(0,0);
        }
        printf("%d\n",piece_len);
    }
    return 0;
}


 

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