zoukankan      html  css  js  c++  java
  • 小木棍 [数据加强版]

    洛咕

    双倍经验---多组数据

    题意:乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50.现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度.给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度.

    分析:首先读入的时候把长度大于50的自动过滤掉,剩下n根长度小于等于50的木棍,设这n根小木棍的长度和为(tot),长度最大的为(val).

    我们直接从小到大枚举原始木棍的长度,并通过dfs判断是否合法即可.枚举的下界是一个小木棍的最大长度(val),上界是长度和(tot).设当前枚举的原始木棍的长度为(len),那么(tot)必然要能被(len)整除,否则不合法,若能够被整除,显然我们要是能够拼凑出(sum=tot/len)根长度为(len)的木棍就是合法答案.

    接下来就只要考虑dfs的剪枝操作了.

    一,我们把木棍长度从大到小排序,优先考虑较长的木棍,显然能减少状态数.

    二,既然剪枝一已经把木棍排序了,那么我们干脆固定每次填入的木棍长度是递减的.这个只要dfs的变量增加一个last,表示当前从第last根木棍开始考虑就好了.

    三,假设我们给一根"空"的 填入木棍,也就是当前的木棍长度(cnt=0),那么当填入(a[i])后该搜索状态不合法,那么直接判定当前分支不合法,因为你把(a[i])填入剩下的其它的"空"的,都会是不合法的.

    四,跟三类似,如果我们当前填完了(a[i])之后,填完了一个长度为len的木棍,发现该搜索状态不合法,那么直接判定当前分支不合法,因为你再用别的若干根短的木棍来代替(a[i]),那么接下来搜索下一根木棍还会是不合法的.

    五,如果填入(a[i])不合法,如果(a[i+1]=a[i])那么直接不要考虑填.

    这些剪枝真的是缺一不可.亲测~~~

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=105;
    int n,tot,val,sum,len;
    int a[N],visit[N];
    //当前正在拼第now跟木棒
    //第now跟木棒已经拼出了长度cnt
    //当前已经考虑到了第last根木棍
    inline bool dfs(int now,int cnt,int last){
    	if(now>sum)return true;//sum根木棒都拼完了
    	if(cnt==len)return dfs(now+1,0,1);//当前这根拼完了
    	int fail=0;//剪枝五用的
    	for(int i=last;i<=n;++i){
    		if(!visit[i]&&cnt+a[i]<=len&&fail!=a[i]){
    			visit[i]=1;
    			if(dfs(now,cnt+a[i],i+1))return true;
    			fail=a[i];//记录不要填与a[i]相同长度的木棍了
    			visit[i]=0;//回溯
    			if(!cnt||cnt+a[i]==len)return false;//剪枝三,四
    		}
    	}
    	return false;
    }
    int main(){
    	int nn=read();
    	for(int i=1;i<=nn;++i){
    		int b=read();
    		if(b<=50){//过滤不合法的木棍
    			a[++n]=b;tot+=b;//记录长度和
    			val=max(b,val);//比较最长木棍
    		}
    	}
    	sort(a+1,a+n+1);reverse(a+1,a+n+1);//从大到小排序
    	for(len=val;len<=tot;++len){//枚举原始木棍长度为len
    		if(tot%len)continue;//不能整除肯定不合法
    		sum=tot/len;//要拼凑出sum根木棍
    		memset(visit,0,sizeof(visit));//初始化
    		if(dfs(1,0,1)){
    			printf("%d
    ",len);
    			break;
    		}
    	}
        return 0;
    }
    
    
  • 相关阅读:
    企业微信通讯录替换-JqueryWEUI Picker替换通讯录
    页面window.onload冲突
    企业微信调试工具
    企业微信:错误码:50001 redirect_url 一例问题解决办法
    企业微信通讯录替换-Echarts中使用部门名称
    紫光拼音输入法切换中英文
    企业微信服务商平台申请
    企业微信通讯录替换-根据员工姓名查找工号
    微信开发 40001 invalid credential
    请求验证过程检测到有潜在危险的客户端输入值,对请求的处理已经中止
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11385261.html
Copyright © 2011-2022 走看看