EOJ 1981:Sticks(DFS+剪枝)

題目鏈接:http://www.acm.cs.ecnu.edu.cn/problem.php?problemid=1981

題意:原本有一些等長的木棍,然後他們被弄斷了。現在你想把他們恢復,但是不知道原本的長度和根數。現在希望恢復的原木棍長度越短越好。

分析:
使用迭代加深搜索。枚舉原本木棍的長度進行搜索。需要加以下剪枝方案。

1,排序後由大到小枚舉每根木棍,因爲每根木棍都會被使用,優先選取大的可以減少遞歸深度。
2,待拼木棍長度爲總長度的約數。
3,若有相同長度木棍在之前沒有被選取,則之後不用再考慮此木棍。
4,若無法拼出長度<=SUM/2的小木棍,則只能拼出長度爲sum的小木棍。
5,若當前剩餘第一根木棍無法使用則說明無法完成任務可提前結束dfs,因爲每根木棍都會被使用。
6,若待拼木棍長度爲當前小木棍長度,則說明此木棍爲最後一根小木棍。若在選取了當前這根小木棍還無法完成任務,則這根小木棍無法被使用,同樣結束程序。
7,限制遞歸調用深度。

(該代碼重寫過,詳見http://blog.csdn.net/u013520118/article/details/48417565

代碼:

#include <iostream>
#include <algorithm>
#include <fstream>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>

using namespace std;

const int maxn = 100 + 5;

bool flag;
int n, sum, deep;
int a[maxn], v[maxn];

bool cmp(const int& x, const int& y)
{
    return x > y;
}

bool DFS(int cur, int left, int limit)
{
    if (deep++ > 200000)
        return false;
    if (!cur && !left)
        return true;
    if (!left)
        left = limit;
    for (int i = 0; i < n; ++i)
    {
        if (i > 0 && a[i] == a[i - 1] && !v[i - 1])
            continue;
        if (!v[i] && a[i] <= left)
        {
            v[i] = 1;
            if (DFS(cur - 1, left - a[i], limit))
                return true;
            else
            {
                v[i] = 0;
                if (a[i] == left || left == limit)
                    return false;
            }
        }
    }
    return false;
}

int main()
{
    while (~scanf("%d", &n), n)
    {
        sum = 0;
        flag = false;
        for (int i = 0; i < n; ++i)
        {
            scanf("%d", &a[i]);
            sum += a[i];
        }
        sort(a, a + n, cmp);
        for (int i = a[0]; i <= sum / 2; ++i)
            if (sum % i == 0)
            {
                deep = 0;
                memset(v, 0, sizeof(v));
                if (DFS(n, i, i))
                {
                    flag = true;
                    printf("%d\n", i);
                    break;
                }
            }
        if (!flag)
            printf("%d\n", sum);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章