蓝桥杯 试题 算法训练 Sticks(dfs剪枝)

问题描述

  George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.

       乔治拿了相同长度的木棍,随机切开,直到所有零件的长度最大为50个单位。现在,他想将木棍恢复到原始状态,但是他忘记了原来拥有多少木棍以及它们原本有多长时间。请帮助他,设计一个程序,计算出那些棍子的最小可能的原始长度。所有以单位表示的长度都是大于零的整数。

输入格式

  The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.

       输入包含2行的块。第一行包含切割后的木棍零件数,最多为64根木棍。第二行包含被空格隔开的那些部分的长度。文件的最后一行包含零。

输出格式

  The output should contains the smallest possible length of original sticks, one per line.

       输出应包含最小长度的原始摇杆,每行一根。

样例输入

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

样例输出

6
5

解题思路:

题目上的样例输出错了,我这里改过来了。

最小的原始木棍长度一定能被总长整除,所以从最大的木棍向上找,找最小的原始木棍长度,然后判断是否符合能不能由所有的木棍组成。

判断用深搜。从大到小开始,这样能快一点。剪枝:这个木棍的长度不合适,那么和这个木棍相同的长度都需要剪掉。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
const int N=65;
int sum,len,n; //sum表示木棍总共的长度,len表示木棍的原始长度
int ans=0;//判断成功的标识符
int vis[N];//记录木棍是否被用过
int cmd(int a,int b){
	return a>b;
}
void dfs(int a[],int s,int l,int index)//s表示成功的木块数,l表示当前木板的长度,index表示木板下标 
{
	if(ans) return;
	if(s==sum/len)
	{
		ans=1;
		return;
	}
	for(int i=index;i<n;i++)
	{
		if(vis[i]||!vis[i-1]&&a[i]==a[i-1]) continue; //剪枝 
		if(l+a[i]==len)
		{
			s++;
			vis[i]=1;
			if(s==sum/len)
			{
				ans=1;
				return;
			}
			//找下一个木板的第一块木板
			for(int j=0;j<n;j++)
				if(vis[j]==0)
				{
					dfs(a,s,0,j);
					vis[i]=0;
					if(ans) return;
					return;
				}
			
		}
		if(l+a[i]<len)//如果最后一个木板拼上还是不够长度,就返回。 
		{
			vis[i]=1;
			dfs(a,s,l+a[i],i+1);
			if(ans) return;
			vis[i]=0;
			if(l==0) return;
		}
	}
}
int main(){	
	while(cin>>n,n)
	{
		sum=0;
		ans=0;
		int a[N];
		for(int i=0;i<n;i++)
		{
			cin>>a[i];
			sum+=a[i];
			vis[i]=0;
		}
		sort(a,a+n,cmd);//从大到小排序 
		for(int i=a[0];i<=sum;i++)
		{
			if(sum%i==0)
			{
				len=i;//木板的最小长度 
				for(int i=0;i<n;i++) vis[i]=0;
				dfs(a,0,0,0);
				if(ans) 
				{
					cout<<len<<endl;
					break;
				}
			}
		} 
	}
}

发布了247 篇原创文章 · 获赞 53 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_42391248/article/details/104732177