poj 1011 Sticks (DFS+剪枝)

poj 1011 Sticks (DFS+剪枝)

大家好,又见面了,我是全栈君。

Sticks
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 127771   Accepted: 29926

Description

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.

Input

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.

Output

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

Sample Input

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

Sample Output

6
5

Source

题目链接:http://poj.org/problem?id=1011


题目大意:有n根木棍。用它们拼成一些等长的木棍,求拼出的木棍的最短长度。


解题思路:这题的时间限制特别严格。

DFS+剪枝,剪枝较多。首先由多到少枚举木棍数目num。即从n到1,要满足木棍总长度是num的倍数,且拼出的长度要不小于最长的木棍长度,否则无法拼,搜索到答案后退出循环,保证求出的木棍长最短。

剪枝:1.木棍由长到短排序。

   2.訪问过的木棍或者加上当前木棍长度后超过了目标长度,则跳过本次循环。

   3.若当前木棍和上一根木棍长度同样而且上一根木棍没用到,则跳过本次循环。

   4.dfs中标记開始木棍下标。


代码例如以下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[66],vis[66];
int n,num,m;
bool p;
int cmp(int a,int b)
{
	return a>b;
}
void dfs(int st,int cur,int cnt)
{
	if(p||cnt==num)
	{
		p=true;
		return ;
	}
	for(int i=st;i<n;i++)
	{
		if(vis[i]||cur+a[i]>m)    //訪问过的木棍或者加上当前木棍长度后超过了目标长度,则跳过本次循环
			continue;
		if(i-1&&!vis[i-1]&&a[i]==a[i-1])    //若当前木棍和上一根木棍长度同样而且上一根木棍没用到,则跳过本次循环。
			continue;
		if(a[i]+cur==m)
		{
			vis[i]=1;
			dfs(0,0,cnt+1);
			vis[i]=0;
			return;				//循环里后面的值都在dfs中求过了。这里直接返回上一层
		}
		if(a[i]+cur<m)
		{
			vis[i]=1;
			dfs(i+1,a[i]+cur,cnt);
			vis[i]=0;
			if(cur==0)           //cur为0时,直接返回上一层
				return ;
		}
	}
}
int main()
{
	while(scanf("%d",&n)!=EOF&&n)
	{
		int sum=0;
		p=false;
		memset(vis,0,sizeof(vis));
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			sum+=a[i];
		}
		sort(a,a+n,cmp);
		for(num=n;num>=1;num--)
		{
			if(sum%num||a[0]>sum/num)
				continue;
			m=sum/num;
			dfs(0,0,0);
			if(p)
				break;
		}
		printf("%d\n",m);
	}
	return 0;
}


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115729.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • CIDR地址块及其子网划分(内含原始IP地址分类及其子网划分的介绍)

    CIDR地址块及其子网划分(内含原始IP地址分类及其子网划分的介绍)CIDR地址块及其子网划分1.CIDR概述及其地址块计算  CIDR中文全称是无分类域间路由选择,英文全称是ClasslessInter-DomainRouting,在平常,大家多称之为无分类编址,它也是构成超网的一种技术实现。2.CIDR子网划分3.总结

    2022年4月29日
    98
  • android之onCreateOptionsMenu失效,按菜单键无反应

    做点名app的时候,由于教师端和学生端UI相似,所以用了一套UI框架,结果修改一番之后,点击菜单键无反应,也就是下面的onCreateOptionsMenu不执行了,  @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu);

    2022年3月11日
    232
  • crontab定时任务语法及应用

    crontab定时任务语法及应用

    2021年10月30日
    52
  • 微信公众号推广_微信公众号评论点赞

    微信公众号推广_微信公众号评论点赞原标题:微信公众号分享集赞吸粉方案,人人可复制分享集赞这种方式很早就有了,不仅在微信公众号运营圈子里面盛行,很多做微商、代购的都很喜欢用这种方式吸粉,其优点是操作简单,可行性佳,获粉成本低。小编在自己博客分享了一些吸粉的文章,但很多同学反馈大多数方法操作难度大,需要很大的工作量,其中80%的朋友还觉得不擅长去做这些事情,需要对这些领域有一定的认识,并且不知道这些事情做了之后有没有效果,其实有这种担…

    2025年9月22日
    9
  • idea2022最新激活码 csdn【中文破解版】

    (idea2022最新激活码 csdn)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.htmlLGWSVFD4PZ-eyJsaWNlbnNlSW…

    2022年4月1日
    605
  • python中append函数什么意思_python中append函数用法讲解

    python中append函数什么意思_python中append函数用法讲解python中append函数用法讲解如果在做一个地区的统计工作,可以使用列表来帮助我们。输入汉字或者其他字符,比如“01代表汉族”,那么在写民族的时候有下拉列表,就可以打01,就会自动识别为汉族。列表是用来大规模数据填报的时候使用,在python中,也有很多使用到列表的时候,那你知道如何在列表的末尾添加新的对象?今天,我们就来认识一下python中可以在列表末尾添加元素的append函数。1、a…

    2022年6月15日
    67

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号