当前位置:   article > 正文

洛谷刷题笔记——P1120 小木棍_洛谷p1120

洛谷p1120

参考资料

题目描述

乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过 50 50 50

现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。

给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。

输入格式

第一行是一个整数 n n n,表示小木棍的个数。
第二行有 n n n 个整数,表示各个木棍的长度 a i a_i ai

输出格式

输出一行一个整数表示答案。

样例 #1

样例输入 #1

9
5 2 1 5 2 1 5 2 1
  • 1
  • 2

样例输出 #1

6
  • 1

提示

对于全部测试点, 1 ≤ n ≤ 65 1 \leq n \leq 65 1n65 1 ≤ a i ≤ 50 1 \leq a_i \leq 50 1ai50

思路

搜索

定义cnt表示原始木棍的数量,len表示每根原始木棍的长度,sum表示木棍的总长度。

定义状态(num, pre, last),其中num表示当前正在拼的原始木棍的编号,pre表示上一个使用的小木棍的编号,last表示当前原始木棍的剩余长度

  • 如果last为0,说明当前原始木棍已经拼接完成。此时,如果有numcnt相等,说明所有木棍拼接成功;如果numcnt不相等,则继续拼接下一个原始木棍。
  • 如果last不为0,则选择尚未使用的小木棍来拼接该原始木棍。

优化

优化1:仅需要考虑len <= sum/2的情况。

优化2:当前状态为:完成了某个原始木棍的拼接,准备进入下一个原始木棍的拼接。在这一状态下,我们选取一根最长的、尚未使用过的小木棍来进行拼接,如果拼接失败,则无需再考虑其他木棍,直接从当前状态返回。这是因为,所有未使用过的小木棍最终都要被用来拼接成原始木棍,所以选择先从哪根小木棍开始都是一样的。也就是说,当前状态并不能导出拼接成功的状态。

优化3:当前状态为:尚未完成该原始木棍的拼接,且选择了一个长度恰好为last的小木棍。如果上述选择导致拼接失败,则无需再考虑其他小木棍,直接从当前状态返回。这是因为,如果当前状态能导出一个拼凑完成的状态,那么这个长度为last的木棍在之后也必须要被使用。显然,在剩余小木棍较多的当前状态下,选择长度为last的小木棍都不能完成拼接,在后面剩余小木棍更少的状态下,度为last的小木棍一定也不能完成拼接。也就是说,当前状态并不能导出拼接成功的状态。

优化4:使用二分查找的方法,找到第一个长度<= last的小木棍的编号,然后从该编号开始选择。需要特别注意的是,二分查找的左边界可以优化为pre+1

优化5:预处理Next[x]数组,存储第一个长度< x的小木棍的下标。

代码实现

#include<bits/stdc++.h>
#define maxn 70
using namespace std;

int n;
int a[maxn];
int sum = 0;
int M = 0;
int m = 0;
bool vis[maxn];
int Next[maxn];
bool flag = false; 
int cnt, len;

bool cmp(int x, int y){
	return x>y;
} 

//num:当前正在拼的是第几个原木棍 
//pre:上一个使用的小木棍的编号
//last:拼完这个原木棍,还需要的长度 
void dfs(int num, int pre, int last){
	//当前原木棍拼成功了 
	if(last==0){
		//所有木棍拼凑成功 
		if(num==cnt){
			flag = true;
			return;
		}
		else{
			for(int i=1;i<=n;i++){
				if(vis[i]) continue;
				vis[i] = true;
				dfs(num+1, i, len-a[i]);
				vis[i] = false;
				if(flag) return;
				return;		//优化2 
			}
		}
	} 
	else{
		//二分查找第一个长度小于剩余长度的小木棍
		int L=pre+1, R=n, mid, pos=n;
		while(L<=R){
			mid = (L+R)>>1;
			if(a[mid]<=last){
				pos = mid;
				R = mid-1;
			}
			else{
				L = mid+1;
			}
		} 
		for(int i=pos;i<=n;i++){
			if(vis[i]) continue;
			vis[i] = true;
			dfs(num, i, last-a[i]);
			vis[i] = false;
			if(flag) return;
			if(last==a[i]) return;
			if(a[i]==m) continue;		//优化3 
			else i = Next[a[i]]-1;
		} 	
	} 
} 

int main(){
	memset(vis, 0, sizeof(vis));
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum += a[i];
	}
	sort(a+1, a+n+1, cmp);
	M = a[1];
	m = a[n];
	//预处理next
	int temp = a[1];
	for(int i=2;i<=n;i++){
		if(a[i]!=temp){
			Next[temp] = i;
			temp = a[i];
		}
	}
	for(int k=M;k<=sum/2;k++){
		if(sum-(sum/k)*k!=0) continue;
		flag = false;
		vis[1] = true;
		cnt = sum/k;
		len = k;
		dfs(1, 1, k-a[1]);
		vis[1] = false;
		if(flag){
			cout<<k;
			return 0;
		}
	}
	cout<<sum;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/590091
推荐阅读
相关标签
  

闽ICP备14008679号