HDU - 1455-经典搜索-剪枝

给你m个长。第一道剪枝的搜索,给你一些棍子,
把这些棍子分成k份,问每份的最小长度
可以是一份,所以每份的最大长度就是sumO(∩_∩)O哈哈~
但是问的是最小长度,方法是dfs搜索。
策略是用一个记录合成的棍子数目,另一个是合成的长度
最后一个。
两种写法
注意1 用了灰常灰常牛逼的回溯,所以每次不用初始化数组咯。
(自己领悟)
2 两处剪枝,一处剪枝其实就是让大家就地解散的意思。
一处是有一个串没用到,相同的也不用了。去也一个德行。另一处
如果有一个第一次都没用到,那么他肯定会被舍弃。
说明他一个已经比要组成的大了,大家就地解散吧
第一个代码好,第二个太笨重了。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn=200;
int c;
int m;
int l;
vector<pair<int,bool> >node;
int cmp2(pair<int,bool> q,pair<int,bool> q2)
{    return q.first>q2.first;
    //以从小到大的顺序排列
}
bool dfs(int t,int len,int pos)
{    if(t==c+1) return true;
      if(len==l) return dfs(t+1,0,0);
    for(int i=pos;i<m;i++)
    {  if(!node[i].second&&node[i].first+len<=l)//可以等于哦
        {   //满足条件,可以放入了;
            node[i].second=true;
            if(dfs(t,len+node[i].first,i+1))
                return true;
                node[i].second=false;
            if(len==0) return false;
            while(i+1<m&&node[i].first==node[i+1].first)
                i++;
        }
    }
   return false;
}
int main()
{
int a;
     while(~scanf("%d",&m))
     {  node.clear();
         if(m==0) break;
         int sum=0;
        for(int i=0;i<m;i++)
         {  scanf("%d",&a);
            sum+=a;
             node.push_back(make_pair(a,false));
         }
         sort(node.begin(),node.end(),cmp2);
         for(l=node[0].first;l<=sum;l++)
         {   if(sum%l!=0)  continue;
              c=sum/l;
              if(dfs(1,0,0))
              {  printf("%d\n",l);
                 break;

              }
         }
     }
return 0;
}
#include<cstdio>    
#include<cstring>    
#include<cmath>    
#include<cstdlib>    
#include<iostream>    
#include<algorithm>    
#include<vector>    
#include<map>    
#include<queue>    
#include<stack>   
#include<string>  
#include<map>   
#include<set>  
#define eps 1e-6   
#define LL long long    
using namespace std;    

const int maxn = 70;  
const int INF = 0x3f3f3f3f;  
int n, sumv, target, aim;//target表示目标的棍子个数,aim表示目标的棍子长度   
int stick[maxn], vis[maxn];  
bool cmp(int a, int b) {  
    return a > b;  
}  

void init() {  
    sumv = 0;  
    for(int i = 0; i < n; i++) {  
        cin >> stick[i]; sumv += stick[i];  
    }  
    sort(stick, stick+n, cmp);  
}  

bool dfs(int cnt, int len, int pos) {  
    if(cnt == target) return true;  
    if(len == aim) return dfs(cnt+1, 0, 0);   
    for(int i = pos; i < n; i++) {                         //从大到小排序后,按顺序搜索   
        if(!vis[i] && len+stick[i] <= aim) {  
            vis[i] = 1;  
            if(dfs(cnt, len+stick[i], i+1)) return true;  
            vis[i] = 0;                                       
            if(len == 0) return false;                     //如果第一根时失败剪枝   
            while(i+1 < n && stick[i+1] == stick[i]) i++;  //如果下一根长度跟当前的失败的长度一样,剪枝   
        }  
    }  
    return false;  
}  

void solve() {  
    int ans = 0;  
    for(int i = 1; i <= sumv; i++) if(sumv % i == 0) {  
        memset(vis, 0, sizeof(vis));  
        aim = i; target = sumv / aim;  
        if(dfs(0, 0, 0)) {  
            ans = aim; break;  
        }  
    }  
    cout << ans << endl;  
}  

int main() {  
//  freopen("input.txt", "r", stdin);  
    while(scanf("%d", &n) == 1 && n) {  
        init();  
        solve();  
    }  
    return 0;  
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值