• P1120小木棍


    题目传送P1120

    有许多剪枝的搜索

    • 先考虑答案的范围,先把小木棍排个序,原木棍的长一定大于等于最长的一根
    • 然后,就枚举一下原木棍的长度,搜是否能按这个长度拼成所有的木棍,如果能拼成直接就是答案了
    • 确定了原始长度,然后用总长度就能算出原始木棍的条数。如果不能整除的话,肯定不是答案
    • 然后确定搜索的状态,当前拼到第几跟,这一根还剩多长,拼这一根用的上一根小木棍的编号
    • 我们肯定要先拼大的,再用小的去补大的
    • 如果我们用小的凑的话,那些大的很难凑齐
    • 还有一个优化就是,有很多长度相同的小木棍,对于一种长度不能拼的话我们要直接略过剩下和它长度相同的。就预处理出(net)数组
    • 还有剪枝,如果这根小木棍正好等于剩下的长度,却没有成功。这是最优的情况都没有成功,说明这种情况不会合法了
    • 还有剪枝,如果这根小木棍等于原长却没被用上,说明这也是不合法的(这两个剪枝会剪掉4个点

    代码

    #include<iostream>
    #include<algorithm>
    using namespace std;
    inline int read(){
    	int s=0,w=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    	return s*w;
    }
    int n,x,num,tag,s,len;
    int a[100],book[100],net[100];
    bool cmp(int a,int b){
    	return a>b;
    }
    void dfs(int now,int last,int res){
    	if(!res){// now 当前是第几个,last拼的上一段的编号,res剩下的长度 
    		if(now==num) {
    			tag=1;
    			return ;
    		}
    		
    		for(int i=1;i<=n;i++)
    		  if(!book[i]){
    		  	book[i]=1;
    		    dfs(now+1,i,len-a[i]);
    		    book[i]=0;
    		    if(tag) return ;
    		    break;
    		  }
    	}
    	int l=last+1,r=n,mid;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(a[mid]>res) l=mid+1;
    		else r=mid-1;
    	}
    	for(int i=l;i<=n;i++)
    	  if(!book[i]){
    	  	book[i]=1;
    	  	dfs(now,i,res-a[i]);
    	  	book[i]=0;
    	  	if(tag) return ;
    	  	if(a[i]==res||res==len) return ;
    	  	i=net[i];
    	  	if(i==n) return ;
    	  }
    }
    int main()
    {
    	x=read();
    	for(int i=1;i<=x;i++){
    		int xx;
    		xx=read();
    		if(xx<=50) {
    			a[++n]=xx;
    			s+=xx;
    		}
    	}
    	sort(a+1,a+n+1,cmp);
    	for(int i=n;i>=1;i--)
    	  if(a[i]==a[i+1]) net[i]=net[i+1];
    	  else net[i]=i;
    	for(len=a[1];len<=s/2;len++){
    		if(s%len) continue;
    		num=s/len;
    		book[1]=1;
    		tag=0;
    		dfs(1,1,len-a[1]);
    		book[1]=0;
    		if(tag){printf("%d",len);return 0;}
    	}
    	printf("%d",s);
    	return 0;
     } 
    
  • 相关阅读:
    贪心例题
    第十六周总结
    软件工程个人课程总结
    冲刺二十一天
    浅谈async/await
    浅谈设计模式的六大原则
    dotnetcore配置框架简介
    这一次,终于弄懂了协变和逆变
    科个普:进程、线程、并发、并行
    五分钟了解Semaphore
  • 原文地址:https://www.cnblogs.com/Vimin/p/11508254.html
Copyright © 2020-2023  润新知