zoukankan      html  css  js  c++  java
  • 【luogu】【DFS+神剪枝】小木棍(数据加强)

    题目描述

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

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

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

    输入输出格式

    输入格式:

    输入文件共有二行。

    第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤65

    (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!)

    第二行为N个用空个隔开的正整数,表示N根小木棍的长度。

    输出格式:

    输出文件仅一行,表示要求的原始木棍的最小可能长度

    代码

    普通DFS不加last剪枝=44分
    加last剪枝=54分
    加神TM剪枝=100分
    蛤蛤

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <functional>
    #define maxn 520
    #define INF 100000000
    using namespace std;
    
    int n,L,last=1,s[maxn],suml=0,maxl=0,minl=INF,c=0; 
    bool vis[maxn];
    
    bool dfs(int cnt,int len){//剩余cnt根木棍,拼到当前还差len的长度 
        if(cnt==0&&len==0) return 1;//木棍不剩且刚好拼到目标长度就得到答案 
        int x=1;//初始化木棍从最长的开始试拼 
        if(len==0) len=L;//如果上一次刚好拼完一整根L,归零重新开始拼 
        if(len!=L) x=last;//last保存上一次是用s[last]这根木棍来减少len的,那么本次搜索就不必选比s[last]更长的木棍 
                            //这是因为在尝试拼这一根木棍的时候,s[last]以前的都已经尝试过了 
                            //如果说已经开始拼新的一根木棍了,就要从头开始搜没用过的了 
        for(int i=x;i<=n;i++){
            if(vis[i]||s[i]>len) continue;//如果已经被占用,跳过 
            if(i>=1&&!vis[i-1]&&s[i]==s[i-1]) continue;//如果相同长度的不能用,跳过 
            vis[i]=1; last=i;
            if(dfs(cnt-1,len-s[i])) return 1;
            vis[i]=0;
            if(len==L||s[i]==len) return 0;//这步很机智啊,如果开始拼新木棍了,那么任何没有被选过的木棍都要能被选进去才行
                                            //如果有一根木棍刚好可以填满,之后却爆炸了,那肯定也没解
                                            //加上这个剪枝瞬间从50分到100分啊... 
        }
        return 0;
    }
    
    int main(){
        //freopen("in.txt","r",stdin);
        scanf("%d",&n);
        int temp;
        for(int i=1;i<=n;i++) {
            scanf("%d",&temp);
            if(temp>50) continue;
            else {
                s[++c]=temp; suml+=s[c];
            }
        } n=c;
        sort(s+1,s+1+n,greater<int>());
        for(L=s[1];L<=suml/2;L++){
            if(suml%L!=0) continue;//如果目标长度不是sum的因数就可以跳过了
            memset(vis,0,sizeof(vis));
            if(dfs(n,L)){
                printf("%d",L);
                break;
            }
        }
        if(L>suml/2) printf("%d",suml);
        return 0;
    } 
  • 相关阅读:
    【HDU1166】敌兵布阵-单点修改和区间求和
    【HDU1166】敌兵布阵-单点修改和区间求和
    【Ural1028】Stars-线段树和树状数组入门题
    【Ural1028】Stars-线段树和树状数组入门题
    【NOIP2014提高组T3】飞扬的小鸟-完全背包
    【NOIP2014提高组T3】飞扬的小鸟-完全背包
    【POJ2528】Mayor's Posters-线段树+离散化
    【POJ2528】Mayor's Posters-线段树+离散化
    perl use utf8
    encode_utf8 把字符编码成字节 decode_utf8解码UTF-8到字符
  • 原文地址:https://www.cnblogs.com/leotan0321/p/6081381.html
Copyright © 2011-2022 走看看