洛谷 P1120 & WUSTOJ 2575 小木棍 【dfs+剪枝】

题目来源:洛谷:https://www.luogu.org/problemnew/show/P1120
WUSTOJ http://acm.wust.edu.cn/problem.php?id=2575&soj=0
在这里插入图片描述
★想想就气【其实还是自己太菜】 居然被书坑了,但是自己没有一点主观意识,请教了学长才发现 书上的代码是有问题的 !

思路:

采用深搜,但是直接搜肯定是会超时的,必须要巧妙的剪枝~
剪枝1:初始长度的范围一定在 a[1] - sum 之间
剪枝2:所有木棍的和为sum,那么初始长度len 必定可以整除sum
剪枝3:短的木棍拼凑越灵活,从大到小排序可以优化
剪枝4:相同长度的木棍不需要搜索多次
剪枝5:等于是最佳匹配 不必再搜索
还有一些地方有剪枝 不一一说明了~
另外其实二分也可以做,只是数据不大,懒得用233

代码:

#include<bits/stdc++.h> 
using namespace std; 
const int maxn=105; 
int a[maxn]; 
bool vis[maxn],flag; 
int n,m,l; 
void hhh(int k,int last,int len) 
{ 
    if(k==m) {flag=1; return;} 
    if(len==0){ 
        for(int i=1;i<=n;i++) 
        if(!vis[i]){ 
            vis[i]=1; 
            hhh(k+1,i,l-a[i]); 
            vis[i]=0; 
            return ; 
        } 
    } 
    for(int i=last+1;i<=n;i++){ 
        if(!vis[i]&&len>=a[i]){ 
            vis[i]=1; 
            hhh(k,i,len-a[i]); 
            vis[i]=0; 
            if(a[i]==len) break;         // 剪枝5
            int j=i; 
            while(i<n&&a[i]==a[j]) i++;  //剪枝4
        } 
    } 
} 
bool cmp(const int &a,const int &b) {return a>b;} 
int main() 
{ 
    while(cin>>n){ 
        int sum=0; 
        for(int i=1;i<=n;i++){ 
            cin>>a[i]; 
            if(a[i]>50) { 
                i--; 
                n--; 
            } 
            else{ 
            sum+=a[i]; 
            } 
        } 
        sort(a+1,a+n+1,cmp);                    //剪枝3
        for(int i=a[1];i<=sum;i++){             //剪枝1
              if(sum%i==0){                     //剪枝2
                  memset(vis,0,sizeof vis); 
                  vis[1]=1; 
                  flag=0; 
                  m=sum/i; 
                  l=i; 
                  hhh(1,1,l-a[1]); 
                  if(flag){ 
                      cout<<l<<endl; 
                      break; 
                  } 
              } 
        } 
    } 
    return 0; 
} 

猜你喜欢

转载自blog.csdn.net/weixin_43890662/article/details/89048812