hdu 1455 Sticks——dfs经典的题目

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

题意:几根长度的棍子被分成了很多半。问合成多个长度相同的棍子,棍子长度最小是多少。

题解:很明显是dfs。所以我们首先需要找到,这些棍子可能是多长,肯定是最长的棍子的长度到所有棍子长度和之间的某个长度。找到这些可能之后就直接按照这个长度开始搜。想法是搜到和为这个长度之后记录,然后重新再搜,一直到所有棍子都分配自后就完成了。

重要的剪枝:确定每次搜索的起始位置,这个一定是确定的!!!其次就是相同长度的棍子,一个不符合其他的肯定也不符合!所以要用pre记录前面的不符合的棍子长度!

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[200],vis[200],n,flag,ans,sum,ss;
int greedy(int max,int sum);
void dfs(int max,int pos,int value,int depth);
bool compare(int a,int b)
{
      return a>b;

}
int main(){
    freopen("a.txt","r",stdin);
    while(scanf("%d",&n)!=EOF&&n!=0){
        flag=ans=sum=ss=0;
        memset(a,0,sizeof(a));
        memset(vis,0,sizeof(vis));
        int max=0;
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            if(max<a[i]) max=a[i];
            sum+=a[i];
        }
        sort(a,a+n,compare);//从大到小排序为了方便搜索,因为很明显棍子越长他的可变性越小,所以先找长的。
        printf("%d\n",greedy(max,sum));
    }
return 0;
}
//找到有多少种棍子长度的可能性
int greedy(int max,int sum){
    int k=0,res[1000];
    for(int i=max;i<sum;i++){
        if(sum%i==0){
        res[k]=i;
        k++;
        }
    }
    for(int i=0;i<k;i++){
            memset(vis,0,sizeof(vis));
            ss=0;
        dfs(res[i],0,0,0);
        if(ss==1) return res[i];
    }
    return sum;
}
void dfs(int max,int pos,int value,int depth){
    if(ss==1){
        return;
    }
    if(value==max){
        depth++;
        if(depth==sum/max){
        ss=1;
        return;
        }
         dfs(max,0,0,depth);
        return;
    }
    if(pos==n){//超过了棍子长度,说明没有可能性,所以直接返回
        return;
    }
    int pre=-1;//这里pre的用法是为了记录,当前查找的棍子是否符合,不符合的话,就记录下来,在选择其他的时候不和他相同。
    for(int i=pos;i<n;i++){
            if(!vis[i]&&a[i]+value<=max&&a[i]!=pre){
                //首先要保证没有被访问过,其次要判断是否当前的长度加上这个之后小于目标长度,再者就是要求该棍子和前面的不一样。
                pre=a[i];
                vis[i]=1;
                dfs(max,i+1,value+a[i],depth);
                vis[i]=0;
                if(pos==0){return;}
                //神器的剪枝,他的神器之处在于,第一次搜索的时候第棍子的情况肯定符合!!确定了每次搜索的起始位置!!
            }
    }

}

 

posted @ 2015-08-14 23:00  Yvettey  阅读(1180)  评论(0编辑  收藏  举报