【bfs】拯救少林神棍(poj1011)

Description

乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。

Input
输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。

Output
为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。

Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6
5

【思路】:bfs,太恶心了~各种优化

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
using namespace std;
const int maxn=999999999;
const int minn=-999999999;
inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N;
int L;
int length[3000];
int visit[65];
int i,j,k;
int my_comp(int x,int y ) {
    return x>y;
}
int startNo,lastStickNo=-1;
int dfs(int R, int M);

int main() {
    while(1) {
        cin >> N;
        if( N == 0 )
            break;
        int he= 0;/*记录总和*/
        memset(length,0,sizeof(length));
        for( int i = 0; i < N; i ++ ) {
            int n;
            cin >> length[i];
            he+= length[i];
        }
        sort(length,length+N,
             my_comp);
        for( L = length[0]; L <= he/ 2; L ++ ) {
            if( he% L)
                continue;
            memset( visit, 0,sizeof(visit));
            if( dfs( N,L)) {
                cout << L << endl;
                break;
            }
        }
        if( L > he/ 2 )
            cout << he<< endl;
    }
    return 0;
}
int dfs( int R, int M) { /*m表示当前正在拼接的木棍和我们枚举的长度L的差距*/
    if( R == 0 && M == 0 )
        return true;
    if( M==0 ) // 一根刚刚拼完的时候换新的一根
        M=L;
    int start= 0;
    int startNo = 0;
    if( M != L ) //剪枝:不选第一个
        startNo = lastStickNo + 1;
    for( int i =  startNo; i < N; i ++) {
        if( !visit[i] && length[i] <= M) {
            if( i > 0 ) {
                if( visit[i-1] == 0 && length[i] == length[i-1])
                    continue; // 剪枝 如果某次拼接选择长度为S 的木棒,导致最失败,则在 同一位置尝试下一根木棒时,要跳过所有长度为S 的木棒
            }
            visit[i] = 1;
            lastStickNo = i;
            if ( dfs( R - 1, M - length[i]))
                return true;
            else
                /*回溯*/
                visit[i] = 0;
            if( M == L)//剪枝
                return 0;
        }
    }
    return false;
}

猜你喜欢

转载自www.cnblogs.com/pyyyyyy/p/10736561.html