Sticks POJ - 1011 少林神棍 dfs四次剪枝

http://poj.org/problem?id=1011

题意:若干根棍子被截成小段的木棒,现在给你这些木棒,问最短可以拼出的棍子长度。

题解:搜索,dfs(r,m) 二个参数分别代表还剩r个木棒,当前棍子还剩m长度。

从dfs(N,L)搜到dfs(0,0)停止。

棍子从大到小排序

从小到大枚举L

四个剪枝

0.考虑木棒大多都一样长的特殊情况。

多余的枚举:

“如果某个木棒在当前棍子不能用,那么之后必定会用到”

1.第一个木棒回溯时(由于后续无法继续拼接导致不能用),后面总归会还是要把它作为 某棍的第一棒(因为它是第一个也就说明是最长的) 来处理的。所以直接跳到下一种长度。

2.最后一个木棒回溯时(由于后续无法继续拼接导致不能用),试图将其用短棒子代替并得到一解。那么这个木棒可以通过与短木棒们交换来获得另一个之前判掉的解。产生矛盾。

“顺序枚举"

3.前后木棒长短顺序。如果短的在长的前面,说明长的在前面的情况已经被判掉了,当然,长的在前面的情况里必然已经包括了先长后短的情况。

坑:用rep模板的时候,全局变量写在rep里面会被定义成局部的orz 不但里面用不了,循环后也会丢失最后循环结束的数据。

#define _CRT_SECURE_NO_WARNINGS
#include<cstring>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<cstdio>
#include<string>
#include<stack>
#include<ctime>
#include<list>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<sstream>
#include<iostream>
#include<functional>
#include<algorithm>
#include<memory.h>
//#define INF 0x3f3f3f3f
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
#define rep(i,t,n)  for(int i =(t);i<=(n);++i)
#define per(i,n,t)  for(int i =(n);i>=(t);--i)
#define mp make_pair
#define pb push_back
#define mmm(a,b) memset(a,b,sizeof(a))
//std::ios::sync_with_stdio(false);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
void smain();
#define ONLINE_JUDGE
int main() {
    ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    long _begin_time = clock();
#endif
    smain();
#ifndef ONLINE_JUDGE
    long _end_time = clock();
    printf("time = %ld ms.", _end_time - _begin_time);
#endif
    return 0;
}
const int maxn = 4e5 + 100;
const ll mod = 1e7 + 7;
const ll INF = (100000)*(200000ll) + 1000;
int N, L;
int vis[65];
int totallen = 0;
int last;
vector<int>anlength;
stack<int >temp;
bool dfs(int r, int m) {
    if (r == 0 && m == 0) {
        return true;
    }
    if (m == 0) 
    {    m = L; }
    int start = 0;
    if (m!= L) start = last + 1;
    rep(i, start, N-1) {
        if (!vis[i] && anlength[i] <= m) {
            if (i > 0) {
                if (vis[i - 1] == 0 && anlength[i] == anlength[i - 1])continue;//consider all length is same
            }

            vis[i] = 1; last = i;//consider order 
            if (dfs(r - 1, m - anlength[i])) {return true; }
            
            else { 
                vis[i] = 0; 
            if (anlength[i] == m||L == m)return false; //某长度下,  某根棍子的第一根木棒不能用,说明这根木棒废了,直接换下一个长度。 
            //if (anlength[i] == m)return false;//最后一根木棒不能用,直接换下一个长度。
            }
        }
    }
    return false;
}



string s;
int a, b, c,ans;
void Run() {
    rep(i, anlength[0], totallen/2) {
        L = i;
        if (totallen%L)continue;
        mmm(vis, 0);
        if (dfs(N, L)) {
            cout << L << endl;
            return;
        }
    }
     {
        cout << totallen << endl;
    }
}

void smain() {
    while (cin >> N) {
        if (N == 0)break;
         totallen = 0;
        anlength.clear();
        rep(j, 1, N) {
            int n;
            cin >> n;
            anlength.push_back(n);
            totallen += n;
        }
        sort(anlength.begin(), anlength.end(),greater<int>());

        Run();
    }

}

猜你喜欢

转载自www.cnblogs.com/SuuT/p/8953423.html