您的位置:首页 > 其它

Stick ------ 剪枝神题

2016-03-29 21:23 489 查看


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

//  根据所给答案 和 题目要求 最直观的就可以有剪枝的地方 而且 剪枝剪得越早 就越省时省力
//  好的思路也可以省不少的时间
#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;
}


下面附上正确答案

#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;
int n,sum,a[100],goal,visited[100];
bool cmp(int a,int b)
{
return a>b;
}
bool DFS(int now,int index,int mark,int goal)  // mark 已集齐的 原始木棒数量   goal 假设原始木棒长度
{
if(mark*goal==sum)
return true;
for(int i=index;i<n;i++)
{
if(visited[i]||(a[i]==a[i-1]&&!visited[i-1]))  //如果这一个节点 已经 被用了   就不再用了  //如果这个节点和上一个节点相同  并且上一个节点 没有被使用  那么这个节点就也不会被使用了
continue;               //  因为  出现这种情况 的原因只有一种就是 + 这个数值  now 大于了 目标值
if(now+a[i]==goal)
{
visited[i]=1;
if(DFS(0,0,mark+1,goal))
return true;
visited[i]=0;
return false;
}
else
if(now+a[i]<goal)
{
visited[i]=1;
if(DFS(now+a[i],i+1,mark,goal))   //    在已经确定了一个比较大的值之后  继续向后面寻找比较小的值
return true;
visited[i]=0;
if(now==0)
return false;
}
}
return false;
}
int main()
{
while(scanf("%d",&n) == 1 && n)
{
int i;
for(i=sum=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n,cmp);
for(i=a[0];i<sum;i++)//  开始从最长的假设
{
if(sum%i)   //如果不能整除的话  那一定不是 原始 平均长度
continue;
memset(visited,0,sizeof(visited));
if(DFS(0,0,0,i))
{
printf("%d\n",i);
break;
}
}
if(i==sum)
printf("%d\n",sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: