Stick ------ 剪枝神题

这个是自己剪得 , 我感觉已经很不错了  但是不知道哪里出了问题  一直  超时

//  根据所给答案 和 题目要求 最直观的就可以有剪枝的地方 而且 剪枝剪得越早 就越省时省力
//  好的思路也可以省不少的时间
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<string>
#include<sstream>
#include<map>
#include<cctype>
using namespace std;
bool cmp(int a,int b)
{
    return a>b;
}
int a[55],goal,visited[55],mark,result,sum,n,flag;
void DFS_check()    //  我感觉 前面的两个剪枝 就十分的强悍了   但是鉴于  这一道题 比较的 变态 所以  继续剪枝!
{
    if(flag)
        return ;
    if(goal>result)
        return ;
    if(goal==result) //  加上了最后一个数字  这时候 mark 也刚刚好  所以 这个放上面
    {
        mark++;
        goal=0;         //  攒够 一套之后 就直接让 计数器归零
    }
    if(mark*result==sum)//  这时候  是 刚好符合条件    //  这个值 不可能大于 sum
    {
        flag=1;
    }
    for(int i=0;i<n;i++)
    {
        if(!visited[i])     // 没有被访问过
        {
            visited[i]=1;
            goal+=a[i];
            DFS_check();
            goal-=a[i];
            visited[i]=0;
            while(a[i]==a[i+1])
                i++;
        }
    }

    if(flag)
        return ;
}
int main()
{
    while(scanf("%d",&n),n)
    {
        result=sum=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        sort(a,a+n,cmp);   // 将 碎木棒长度 从大到小排序之后 1 :方便操作 2 :在找出答案之后 可以很快的退出 寻找 ,能省不少的时间
        int len=(sum/2)+1;
        for(int i=a[0];i<=len;i++)   //  一个剪枝   ,  这个估计能省去 理论上一半的时间 的时间
        {
            if(sum%i!=0)    //  这里的 i 是假设的 原始木棒长度 //  如果总长度 不能被假设木棒长度整除的话 , 这个假设就是不成立的 .
                continue;
            memset(visited,0,sizeof(visited));
            flag=goal=mark=0;
            result=i;
            DFS_check();
            if(flag)   //  检查 该长度  是否  是  最小的木棒长度
            {
                result=i;     //更新最小木棒长度
                break;
            }
        }
        if(result==0)
            result=sum;
        printf("%d\n",result);
    }
    return 0;
}

 下面附上正确答案

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<math.h>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<vector>
 8 #include<set>
 9 #include<stack>
10 #include<string>
11 #include<sstream>
12 #include<map>
13 #include<cctype>
14 using namespace std;
15 int n,sum,a[100],goal,visited[100];
16 bool cmp(int a,int b)
17 {
18     return a>b;
19 }
20 bool DFS(int now,int index,int mark,int goal)  // mark 已集齐的 原始木棒数量   goal 假设原始木棒长度
21 {
22     if(mark*goal==sum)
23         return true;
24     for(int i=index;i<n;i++)
25     {
26         if(visited[i]||(a[i]==a[i-1]&&!visited[i-1]))  //如果这一个节点 已经 被用了   就不再用了  //如果这个节点和上一个节点相同  并且上一个节点 没有被使用  那么这个节点就也不会被使用了
27             continue;               //  因为  出现这种情况 的原因只有一种就是 + 这个数值  now 大于了 目标值 
28         if(now+a[i]==goal)
29         {
30             visited[i]=1;
31             if(DFS(0,0,mark+1,goal))
32                 return true;
33             visited[i]=0;
34             return false;
35         }
36         else
37         if(now+a[i]<goal)
38         {
39             visited[i]=1;
40             if(DFS(now+a[i],i+1,mark,goal))   //    在已经确定了一个比较大的值之后  继续向后面寻找比较小的值  
41                 return true;
42             visited[i]=0;
43             if(now==0)
44                 return false;
45         }
46     }
47     return false;
48 }
49 int main()
50 {
51     while(scanf("%d",&n) == 1 && n)
52     {
53         int i;
54         for(i=sum=0;i<n;i++)
55         {
56             scanf("%d",&a[i]);
57             sum+=a[i];
58         }
59         sort(a,a+n,cmp);
60         for(i=a[0];i<sum;i++)//  开始从最长的假设
61         {
62             if(sum%i)   //如果不能整除的话  那一定不是 原始 平均长度
63                 continue;
64             memset(visited,0,sizeof(visited));
65             if(DFS(0,0,0,i))
66             {
67                 printf("%d\n",i);
68                 break;
69             }
70         }
71         if(i==sum)
72             printf("%d\n",sum);
73     }
74     return 0;
75 }

 

posted @ 2016-03-29 21:23  X-POWER  阅读(265)  评论(0编辑  收藏  举报