小木棍加强版解题报告

【题目描述】:

简易描述:
给定 \(n(n\leq 65)\)个数值(每一段不超过\(50\)),输出其能够拼成的最小木棒长度;
也就是只有看过题面的人才看的懂。
具体描述 : QwQ


【杂言】:

看到最小值, 由于上两天刷了二分和三分,这个题,我觉得可以用二分,我不会,\(so\ , \ pass\)
我看了一下有一个查看题解,我立马,打开我的小蓝本,我错了,我大大的错了,我是真不知道小蓝本的解法错误,我的时间随着小蓝本在我手中揉捏而逝去1个半小时,气死我了,但是小蓝本的分析和题意解读的挺不错的。

为了写这一篇,博客我分别把哪一步优化去掉,能得多少分,还去看了一下


【思路分析】:

提供其他解法
我们发现有种朴素的做法,那就是我们可以从小到大枚举每一种的长度出现的情况,反正必然是个整数,然后呢,搜索,看一下是否可以用我们现有的木棒拼出来,复杂度大概是\(O(n\times 2^n),\)期望得分,20分,我觉得行,好歹有点分。
考虑对其进行优化:

1.输入的时候扔掉\(length≥50\),题目中提供的
2.我们枚举可能出现的长度是从最大值枚举一直枚举到\(\sum \limits_{i = 1 } ^ n \ len_{i}\) , 其中显然包括了出现的所有情况
3.在进行操作的时候,长木棍肯定是比几根能够拼成同样长度的小木棒要死板一下,所有取小木棒也就是更灵活一些,让短小的能够自由组合,我们枚举小木棒的时候,从大到小枚举
4.原长度是一定可以被总长度整除的,我一开始就是考虑删除50以上的会不会对答案进行干扰,放心,这里一点都不会进行干扰,
5.在进行搜索的时候,我们从上一次搜索的继续,这里选用的是桶,因为数据不是很多的样子,而且可以省去既要记录小木棒长度,又要其编号
6.搜索判断一下搜到的几根木棒是否会大于,那也就没必要搜下去了,返回。
7.木棒原来的长度是一定大于等于所剩下的木棒中,最长的那一根
8.在进行搜索的时候, 如果在搜索的上一次是 0 , 那么意味着根本没法拼
9.如果正常搜索的时候 , \(i\ + \ last \ == len\),但是由于\(now\) 的限制,无法通过,让其返回即可,没必要在进行操作了

注 : 若未进行第优化 8 , 9 。只能得到 54 分的高分, 只有优化 8 , 54分, 只有优化 9 , 78分的高分。

【Code】:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
#define inf 0x3f 
#define QwQ printf("运行过了") ; 
using namespace std ;
inline int read() 
{
	int x = 0 , f = 1 ; char ch = getchar() ;
	while(!isdigit(ch)){ if(ch =='-') f = - 1 ; ch = getchar() ; }
	while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar() ; }
	return x * f ; 
}
int n , cnt , tot , maxn , flag , m ,ans , len , minn;
int num[70];
void prepare()
{
	n = read() ;
	for(int i = 1 ; i <= n ; i++)
	{
		int length = read() ;
		if(length > 50) continue ;
		else 
		{
			num[length]++ ;
			tot += length ;
			maxn = max(maxn , length ) ;
			minn = min(minn , length ) ;
		}
	}
}
bool search(int now , int former , int last )
{
	
	if(now == cnt + 1 ) // 搜索一直不出问题,自然 OK 
	{
		return true ;
	}
	if(former == len) 
	{
		return search(now + 1 , 0 , maxn ) ;
	}
	for(int i = last ; i >= minn ; i--)
	{
		if(i + former <= len && num[i] ) //棍子相加不能超过限制, 并且这棍子还有 
		{
			num[i] -- ; 
			if(search(now , i + former , i)) 
			{
				return true ;	
			}
			num[i] ++ ;//回溯
			if(former == 0 || former + i == len)
			{
				return false ; 
			}
		}
	}
	return false ;
}
signed main()
{
	prepare() ;	
	for(len = maxn ; len <= tot ; len ++)
	{
		if(tot % len == 0)
		{
			cnt = tot / len ;
			if(search(1 , 0 , maxn ) )
			{
				ans = len ; 
			}
		}
	}
	printf("%d" , ans ) ;
	return 0 ;
} 
posted @ 2020-12-20 11:52  SkyFairy  阅读(118)  评论(0编辑  收藏  举报