poj dfs相關之1011 Sticks

poj dfs相關之1011 Sticks

這道題是比較經典的回溯題,而且剪枝很重要,不然會超時:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 70;
int n, ans, len,num;
int stick[maxn];
bool mark[maxn];
bool cmp(int i, int j)
{
    return i > j;
}
bool dfs(int sum, int dep, int i)
{

    if (dep == num - 1)//剪枝1:與dep==num等價,剩下的構成最後一個小棒
    {
        ans = 1;
        return true;
    }
    if (ans)
        return true;
    int t, tmp;
    for (t = i; t < n; t++)
    {
        if (mark[t] == 1)
            continue;
        mark[t] = 1;
        if (sum + stick[t] < len)
        {
            if (dfs(sum + stick[t], dep, i + 1))
                return true;
        }
        else if (sum + stick[t] == len)
        {
            if (dfs(0, dep + 1, 0))
                return true;
        }

        mark[t] = 0;
        if (sum == 0)//剪枝2:如果第一個小棒就找不到組合的話(此時所有遞歸都退出到這兒,和爲0),則break。這裏如果不剪枝的話一定會超時
            break;
        while (stick[t] == stick[t + 1] && t < n)t++;//剪枝3,stick[t]不行的話,與他相同的也不行(前提是降序排列)
    }
    return false;

}
int main()
{
    freopen("1.txt", "r", stdin);
    int i, j, k, sum;
    while (scanf("%d", &n) != EOF&&n != 0)
    {
        k = 0;
        sum = 0;
        for (i = 0; i < n; i++)
        {
            scanf("%d", &stick[i]);
            k = max(k, stick[i]);
            sum += stick[i];
        }
        sort(stick, stick + n, cmp);
        for (len = k; len <= sum; len++)//剪枝4:循環從K開始
        {
            if (sum%len == 0)
            {
                memset(mark, 0, sizeof(mark));
                ans = 0;
                num = sum / len;
                dfs(0, 0, 0);
                if (ans)
                {
                    printf("%d\n", len);
                    break;
                }
            }
        }
    }
}
發佈了41 篇原創文章 · 獲贊 0 · 訪問量 7475
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章