ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【解题报告】洛谷P1120 小木棍

2021-10-18 21:01:54  阅读:195  来源: 互联网

标签:洛谷 木棒 len int 解题 原始 木棍 P1120 include


【解题报告】洛谷P1120 小木棍

题目链接

https://www.luogu.com.cn/problem/P1120

思路

——摘自《算法竞赛进阶指南》

我们可以从小到大枚举原始木棒的长度 \(len\) , 它应该是所有木棍长度的和 \(sum\) 的因数,并且原始木棒的根数 \(cnt\) 应该等于 \(\dfrac {sum} {len}\)

对于每一个枚举的 \(len\) ,我们可以一次搜索每根原始木棒由哪些木棍拼成,具体的讲,也就是搜索的状态是 :已经拼好的原始木棒的数量,正在拼的原始木棒的当前长度,每个木棍的使用情况,在么一个状态下,我们从还没有用的木棍中选择一个,尝试拼到当前的原始木棒中,然后递归到新的状态,递归边界就是成功拼好 \(cnt\) 根原始木棒,或者因为无法继续拼接而失败

这个算法的效率比较低,我们可以进行几类剪枝:

  1. 优化搜索顺序

把木棒从大到小排序,优先尝试比较长的木棍

  1. 排除等效冗余

可以限制先后加入一根原始木棒的木棍长度是递减的,这是因为先拼上一根长度为 \(x\) 的木棍,再拼上一根长度为 \(y\) 的木棍,和先拼 \(y\) 再拼 \(x\) 一毛一样,所以只用搜索其中一种

对于当前的原始木棒,记录最近一次尝试拼接的木棒的长度,如果分支搜索失败回溯,就不再尝试向该木棒中拼接其他相同的木棒,因为必定也会失败

如果当前原始木棒中,尝试拼入的第一根木棍的递归分支就失败了,那这个分支肯定失败,立马回溯,这是因为在拼入这根木棒之前,面对的所有的木棍都是空的,这些木棒都是等效的,木棍拼在当前的木棒里面失败,拼在其他的木棒里面也一定会失败

如果在当前的原始木棒里面拼入一根木棍之后,木棒恰好被拼接完整,并且接下来拼接剩余原始木棒的递归分支返回失败,那么就直接判定当前的分支失败,立即回溯,该剪枝可以使用贪心来解释,再用1根木棍敲好拼完当前的原始木棒必然比再用若干根木棍拼完当前的木棒更加好

这样运用一些等效性和贪心就剪掉了搜索树上面的很多分支,提高了搜索的效率

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
const int maxn=3300;
int n,ans,res,tot,mx,sum;
int s,l;
int a[70];
bool vis[maxn];
bool dfs(int now,int len,int cnt)
{
	if(now>s) return true;
	if(len==l)
	return dfs(now+1,0,1);
	int f=0;
	for(int i=cnt;i<=tot;i++)
	{
		if(!vis[i]&&len+a[i]<=l&&f!=a[i])
		{
			vis[i]=true;
			if(dfs(now,len+a[i],i+1))
			return true;
			f=a[i];
			vis[i]=false;
			if(len==0||len+a[i]==l)
			return false;
		}
	}
	return false;
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		if(x>50) continue;
		a[++tot]=x;
		mx=max(mx,x);
		sum+=x;
	}
	sort(a+1,a+tot+1);
	reverse(a+1,a+tot+1);
	for(l=mx;l<=sum;l++)
	{
		if(sum%l) continue;
		s=sum/l;
		memset(vis,false,sizeof(vis));
		if(dfs(1,0,1))
		break;
	}
	cout<<l<<'\n';
	return 0;
}

标签:洛谷,木棒,len,int,解题,原始,木棍,P1120,include
来源: https://www.cnblogs.com/wweiyi2004/p/15422261.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有