[DFS+剪枝]POJ 1011/HDOJ 1455/HOJ 1049 Sticks

传送门:

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

HDOJ:http://acm.hdu.edu.cn/showproblem.php?pid=1455

HOJ:http://acm.hit.edu.cn/hoj/problem/view?id=1049

Sticks

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5206    Accepted Submission(s): 1456


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


解题报告:

这是一道经典的搜索剪枝题。

解法:

在刚开始搜索组成一支新的长为 L 的木棍时,我们总是以当前最长的,未被使用的,木棍开始,如果搜索不成功,那么以比它短的开始, 这时也一定不能取得全局的成功。因为每一支题目给出的木棍都要被用到。代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
bool visited[65];//标记是否访问过
int snum; //分火柴棍
int sum;//总分火柴棍长度之和
int sticks[65];//储存分火柴棍
int l;//合起来每根火柴棍长度
int num;//合起来有多少根火柴棍
bool dfs(int s,int slen,int pos){//s当前已经分配好的火柴棍,slen当前总长度,pos当前第几个火柴棍
    if(s==num)
        return true;
    bool sign =(slen==0?true:false);
    for(int i=pos+1;i<snum;i++){
        if(visited[i]==true)    //该根火柴访问过
            continue;
        if(slen+sticks[i]==l){
            visited[i]=true;
            if(dfs(s+1,0,-1))
                return true;
            else{
                visited[i]=false;
                return false;
            }
        }
        else if(slen+sticks[i]<l){
            visited[i]=true;
            if(dfs(s,slen+sticks[i],i)) //没达到继续加下一根
                return true;
            else{
                visited[i]=false;
                if(sign)
                    return false;
            }
        }
    }
    return false;
}
bool cmp(int a,int b){
    return a>b;
}
int main(){
    while(scanf("%d",&snum)==1&&snum){
        sum=0;
        for(int i=0;i<snum;i++){
            scanf("%d",&sticks[i]);
            sum+=sticks[i];
        }
        sort(sticks,sticks+snum,cmp);
        for(l=sticks[0];l<=sum;l++){
            if(sum%l==0){
                num=sum/l;
                memset(visited,false,sizeof(visited));
                if(dfs(1,0,-1)){//第一次找到的肯定是最大的
                    printf("%d\n",l);
                    break;
                }
            }
            else
                continue;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值