UVa 307 小木棍(Sticks)

题目:略

思路:

1 木棍原来最小长度应该是当前所有木棍中最长木棍到木棍总和的一个范围内
2 剪枝很重要,题目没有指定明确数据范围,下列几个剪枝,去掉一个都TLE

算法解释:
排序木棍,为了更加快速的求解
也为了 下列代码中/****/注释这行的剪枝,非常重要
假设 九个木棒的长度为 5 2 1 5 2 1 5 2 1
如果没有排序 最后取的结果可能是 2 + 2 + 1 + 1 = 6 这样的话 left == sum ./ (end +1) 剪枝发生错误
这个递归的代码其实是解决了一个可能的最小长度后,如果还有最小长度,直接不管了,为什么
因为排序后是 5 5 5 2 2 2 1 1 1
只可能选 5 + 1 5 + 1 5 + 1 2 + 2 + 2
如果排序后是 5 5 5 3 2 2 1 1 1
则是 5 + 1 5 + 1 5 + 1 3 + 2
这个时候由于 3+ 2 这里已经不可能有 6
递归回去到3的时候 不再进行 3 + 另一个2
原因很简单,因为是按顺序的,前面的每个凑成最小长度的木棍都是合理的。
这里就进行了大量的剪枝。

#include
#define LL long long
using namespace std;
const int maxn = 100 + 5;
int stick[maxn];
int sum, maxc;
bool vis[maxn];

bool dfs(int cur, int end, int left, int pos, int n) {
    if(cur == end) return true;
    for(int i = pos; i < n; i++) {
        if(!vis[i] && stick[i] < left) {
            vis[i] = 1;
            if(dfs(cur, end, left - stick[i], i + 1, n)) return true;
            vis[i] = 0;
            if(left == sum / (end + 1)) return false; /****/
        }
        if(!vis[i] && stick[i] == left) {
            vis[i] = 1;
            if(dfs(cur + 1, end, sum / (end + 1), 0, n)) return true;
            vis[i] = 0;
            return false;
        }
    }
    return false;
}

bool cmp(int a, int b) {
    return a > b;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    while (cin >> n) {
        if(n == 0) break;
        sum = 0;
        maxc = -1;
        for(int i = 0; i < n; i++) {
            cin >> stick[i];
            if(stick[i] > maxc) maxc = stick[i];
            sum += stick[i];
        }
        sort(stick, stick + n, cmp);
        //cout << stick[0] << endl;
        bool flag = false;
        int i;
        //cout << sum  << " " << maxc << endl;
        for(i = maxc; i < sum; i++) {
            memset(vis, 0, sizeof(vis));
            if(sum % i != 0) continue; //无法整除
            //cout << i << endl;
            if(dfs(0, sum / i - 1, i, 0, n)) { 
                flag = true;
                break;
            }
        }
        cout << (flag ? i : sum) << endl;
    }

    return 0;
}

你可能感兴趣的:(UVA,dfs)