• 洛谷——P1120 小木棍 [数据加强版]


    P1120 小木棍 [数据加强版]

    题目描述

    乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050。

    现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

    给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

    搜索+剪枝

    先贴一个70分的代码:

    #include<bits/stdc++.h>
    
    #define N 1010
    using namespace std;
    
    int n,a[100],tot,sum,sh[N];
    
    bool vis[N],flg,pvis[100];
    
    void scz(int k){
        for(int i=1;i<=k;i++) pvis[sh[i]]=1;
    }
    
    void dfs(int k,int l,int L){
        if(l==L){
            ++sum;
            if(sum*L==a[0]) flg=1;
            scz(k-1);
            return;
        }
        for(int i=1;i<=tot;i++){
            if(!vis[i]&&l+a[i]<=L&&!pvis[i]){
                vis[i]=1;sh[k]=i;
                dfs(k+1,l+a[i],L);
                vis[i]=0;
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[++tot]);
            if(a[tot]>50) --tot;
    //        a[0]+=a[tot];
            a[n+1]=max(a[n+1],a[tot]);
        }
        for(int i=0;i<=tot;i++)
            a[0]+=a[i];
    //        ,printf("%d
    ",a[i]);
    //    printf("%d
    ",a[0]);
        
        for(int i=a[n+1];i<=a[0];i++){
            memset(pvis,0,sizeof(pvis));
            if(a[0]%i==0){
                sum=0;
                dfs(0,0,i);
                if(flg){
                    printf("%d
    ",i);
                    break;
                }
            }
        }
        return 0;
    }

    剪枝大法好

    #include<bits/stdc++.h>
    
    #define N 1010
    using namespace std;
    
    int n,a[100],tot,sum,L,last;
    
    bool vis[N];
    
    bool dfs(int R,int M){//还剩下的木棍,需要拼凑的木棍长度 
        if(R==0&&M==0)
            return true;
        if(M==0) 
            M=L;
        int st=1;
        if(M!=L) 
            st=last+1;//剪枝4,从下一根更短的进行尝试 ,而不是从头开始 
        for(int i=st;i<=tot;i++){
            if(!vis[i]&&a[i]<=M){
                if(i>1&&vis[i-1]==false&&a[i]==a[i-1]){
                    continue;
                }//剪枝1,如果上一个没被选中且当前这一个与上一个长度相等 
                vis[i]=1;last=i;
                if(dfs(R-1,M-a[i])) return true;
                else vis[i]=0;
                if(M==L||a[i]==M)
                    return false;//剪枝2,如果第一根木棍不能更新,那么就永远不能更新 
                    //剪枝3 如果当前木棍在==M的情况下不能成功,那就不可能成功 
            }
        }
        return false;
    }
    
    bool cmp(int x,int y) {
        return x>y;
    }
    
    int main() {
        scanf("%d",&n);
        for(int i=1; i<=n; i++) {
            scanf("%d",&a[++tot]);
            if(a[tot]>50) --tot;
            a[n+1]=max(a[n+1],a[tot]);
        }
        for(int i=0; i<=tot; i++)
            a[0]+=a[i];
        sort(a+1,a+1+tot,cmp);
        
        
        for( L=a[n+1]; L<=a[0]/2; L++) {
            memset(vis,0,sizeof(vis));
            if(a[0]%L) continue;
            if(dfs(tot,L)){
                printf("%d
    ",L);
                break;
            }
        }
        if(L>a[0]/2) printf("%d
    ",a[0]);
        return 0;
    }

    剪枝方法总结:

    1) 要选择合适的搜索顺序 如果一个任务分为 A, B, C…..等步骤(先后次序无关), 要优先尝试可能性少的步骤

    2) 要发现表面上不同,实质相同的重复状态,避免重复的搜索

    3) 要根据实际问题发掘剪枝方案

  • 相关阅读:
    Oracle 游标
    对"com1"的访问被拒绝
    几种不伤身体的速效减肥秘方 生活至上,美容至尚!
    护肤必备,教你如何护理肌肤 生活至上,美容至尚!
    九种食物摆脱便秘烦恼 生活至上,美容至尚!
    1个多月就能看到效果的减肥大法 生活至上,美容至尚!
    防晒涂抹四大要领,让你远离日晒痛苦 生活至上,美容至尚!
    晚间保养四部曲 轻松护肤有妙招 生活至上,美容至尚!
    夏日驱蚊虫蟑螂的最好办法! 生活至上,美容至尚!
    睡前一分钟打造完美下半身 生活至上,美容至尚!
  • 原文地址:https://www.cnblogs.com/song-/p/9636019.html
Copyright © 2020-2023  润新知