• 一本通 木棒问题(dfs深搜剪枝)


    一本通 小木棍

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

    输入格式

    第一行为一个单独的整数 表示砍过以后的小木棍的总数。 第二行为 个用空格隔开的正整数,表示 根小木棍的长度。

    输出格式

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

    样例

    样例输入

    9

    5 2 1 5 2 1 5 2 1

    样例输出

    6

    思路在代码注释里,第一次理解剪枝,真让人头大...思路混乱ing

    #include <string.h>
    #include <stdio.h>
    #include <algorithm>
    using namespace std;
    int n,mid,sum,res,ans;
    int a[70],vis[70];
    bool cmp(int x,int y)
    {
    	return x>y;
    }
    int  dfs(int len,int sta,int now)//原长木棍剩下多长,第几根,以匹配的组数(一组就是这些木棍共同拼成了一根原长木棒) 
    {
    	int i,j;
    	if (now==res)//如果顺利完全匹配的根数==原本木棍的根数,成功 
    		return 1;
    	if (len==0)//这一根原木棒剩余长度为0了 
    		if (dfs(ans,1,now+1))//这一根匹配完了,下一根重新从1开始找是否有匹配。没事有vis[]呢。 
    			return 1;
    	//----------正式匹配区---------------------------------------------------------------------------
    	for (i=sta; i<=n; i++)
    	{ 
    		if (!vis[i]&&a[i]<=len) 
    		{
    			vis[i]=1;
    		
    			if (dfs(len-a[i],i+1,now))//这一根可以用,趁着剩余长度(len)不为零,继续找下一根 
    				return 1;
    			//如果幸运地连续搜到的几根长度加起来等于原长,那就一路返回1了
    			//一旦有不符合条件的,看见下面的return 0没?这条路径毁了; 
    			vis[i]=0;
    		
    		//-------------来吧,开森剪枝,反正你想不到------------------------------- 
    		//出现剪枝的条件一定是某个棍不匹配,需要继续寻找匹配项
    			if (len==ans||len==a[i])  break;
    			/*1.第一根木棒是不成功的(中途有一个木棍怎样都匹配不上了,
    			看着那么多小木棍,就是不能让len==0,那只有放弃这个组合了,重新从第一根开始组合)
    			2.最后一根木棒不成功 
    			len==a[i],剩余长度等于a[i],也就是说在这一步之前,上面的dfs为dfs(0,i+1,now),然后len==0,
    			最后dfs(ans,1,now+1)失败,说明这一根之后再无可匹配的木棍,返回0 
    			
    			怎么感觉这两个剪枝差不多啊,而且去掉第二个剪枝照样可以AC,去掉第一个剪枝就超时了 
    			*/
    			 
    			while(a[i]==a[i+1])
    				i++;//去重剪枝 
    			//如果这一根不成立,那么长度和它一样的肯定也不成立
    		}
    	}
    	return 0;
    }
    int main()
    {
    	int i,j;
    	scanf("%d",&n);
    	for (i=1; i<=n; i++)
    	{
    		scanf("%d",&a[i]);
    		sum+=a[i];
    	}
    	sort(a+1,a+1+n,cmp);
    	for (i=a[1]; i<=sum; i++) 
    	{
    		//枚举,最长的木棍到总长度sum之间肯定有一个最小值是木棍原长 
    		if(sum%i!=0) //由于是几根一样原长的木棍,所以最后sum一定可以被原长整除 
    			continue;
    			
    		res=sum/i;//如果i是原长,那么res就是原来有几根原长的木棍。 
    		ans=i;// 原长,不多说 
    		if(dfs(i,1,0))//以i为原长搜索,如果成功,那最小原长度就是i了 
    		{
    			printf("%d
    ",i);
    			return 0;
    		}
    	}
    	return 0;
    }
    /*
    剪枝1:
    不要在同一位置多次尝试相同长度的木棒
    
    剪枝2:
    如果以后拼接失败,需要重新调整第i根棍子的拼法,
    则不用考虑替换第i根棍子中的第一根木棒。
    如果在不替换第一根木棒的情况下,怎么都无法成功,那么就要推翻第i-1根棍子的拼法。
    如果不存在第i-1根棍子,那么就推翻本次假设的棍子长度,尝试下一个长度。
    
    剪枝3:
    不要希望通过仅仅替换已拼好棍子的最后一根木棒就能够改变失败的局面。
    
    剪枝4:
    拼每一根棍子的时候,应该确保已经拼好的部分,长度是从长到短排列的。
    */
  • 相关阅读:
    cass9.1打开程序错误——加载arx失败
    c#类型和变量
    AutoCAD启动缓慢
    XAML特殊字符
    静态GPS时间修改
    AutoCAD的IntersectWith方法
    Visual studio2010开发AutoCAD2008、2006 启动调试问题
    安装CAD2006装好了为什么不能用,显示系统错误无法启动此程序,因计算机丢失aclst.dll。尝试重新安装该程序以解
    安装AutoCAD2006时,提示已终止安装
    CASS 2008的野外操作码
  • 原文地址:https://www.cnblogs.com/shidianshixuan/p/13905503.html
Copyright © 2020-2023  润新知