1. 程式人生 > >【DFS+多次剪枝】HDU1455Sticks【POJ少林神棍】

【DFS+多次剪枝】HDU1455Sticks【POJ少林神棍】

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1455

Problem Description George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero. 

Input The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.

Output The output file contains the smallest possible length of original sticks, one per line. 

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

這是個很好的題目,綜合力很強!!!

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool cmp(int a,int b){return a>b;}
int L,n,sum;
int a[1010];
int vis[1010];
//int ss,s;
int dfs(int s,int N,int M)        //  N:剩餘木棍總數;M:拼成一根長度為L的木棍還需M長度;s為開始的位置(剪枝)
{
    if(N==0&&M==0) return 1;        //  表示剛好可以拼成長度為M的小木棍;
    if(M==0) M=L,s=0;           //  拼完一根,M重新賦值為L,拼下一根;
    //int ss=0;
    //if(M!=L) ss=s+1;
    for(int i=s;i<n;i++){
        if(!vis[i]&&a[i]<=M){       //  沒有用過的,且長度小於M;
            if(i&&!vis[i-1]&&a[i]==a[i-1]) continue;  //  剪枝,i-1,i的長度一樣,如果i-1沒有被使用,那麼i也不可能被使用;
            vis[i]=1;
            //s=i;
            if(dfs(i+1,N-1,M-a[i])) return 1;
            else{
                vis[i]=0;
                if(M==L) return 0;      //  第一根就不適用(剪枝);
                if(M==a[i]) return 0;   //  剪枝;如果a[i]剛好可以湊成一根完整的木棍,但是沒有用,那麼無法所有的木棍長度都為L;
            }
        }
    }
    return 0;
}
int main()
{
    cin.sync_with_stdio(false);
    while(cin>>n&&n){
        sum=0;
        for(int i=0;i<n;i++){
            cin>>a[i];
            sum+=a[i];
        }
        sort(a,a+n,cmp);
        for(L=a[0];L<=sum/2;L++){
            if(sum%L) continue;         //  如果無法整除,不用考慮;
            memset(vis,0,sizeof(vis));
            if(dfs(0,n,L)){
                cout<<L<<endl;
                break;
            }
        }
        if(L>sum/2) cout<<sum<<endl;        //  只能合成一根木棍;
    }
    return 0;
}