蓝桥杯 算法训练 粘木棍

该博客探讨了如何使用递归算法解决蓝桥杯竞赛中的一个问题,即如何将N根木棍粘贴成M个长木棍,使得最长和最短木棍的差距最小。提供了两种递归解决方案,一种是直接枚举,另一种是优化后的合并策略,旨在减少无效计算。通过这两种方法,博主展示了如何在限制时间内找到最小差距。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

蓝桥杯 算法训练 粘木棍

题目描述

  • 资源限制
    时间限制:1.0s 内存限制:256.0MB
  • 问题描述
    有N根木棍,需要将其粘贴成M个长木棍,使得最长的和最短的的差距最小。
  • 输入格式
    第一行两个整数N,M。
    一行N个整数,表示木棍的长度。
  • 输出格式
    一行一个整数,表示最小的差距
  • 样例输入
    3 2
    10 20 40
  • 样例输出
    10
  • 数据规模和约定
    N, M<=7

方案1 递归 枚举

#include<iostream>
#include<cmath>

using namespace std;

int n;				//n个木棍 
int m;				//粘贴成m个长木棍
int sticks[7];		//sticks[i]: 第i+1个木棍长度 
int long_sticks[7];	//long_sticks: 第i+1个长木棍的长度 
int MIN;			//最短的长木棍长度 
int MAX; 			//最长的长木棍长度 
int ans=-1; 		//最小的差距


//函数功能:    求当前位置cur 上的木棍应该粘贴在哪根长木棍上 
void f(int cur, int n, int m, int sticks[], int long_sticks[], int MAX){
	//全部分完 
	if(cur == n){
		MIN = 0;
		//判断是否有长木棍长度为0 , 若没有找出最短的长木棍 
		for(int i=0; i<m; i++){
			//长木棍长度为0  ,  不合题意 
			if(long_sticks[i]==0){
				return ;
			}else{
				if(MIN!=0){
					MIN = min(MIN, long_sticks[i]);
				}else{
					MIN = long_sticks[i];
				}
			}
		}
		//更新 最小的差距
		if(ans!=-1){
			ans = min(ans, (MAX-MIN));
		}else{
			ans = (MAX-MIN);
		}
		return ;
	}
	
	//没有分完   遍历当前位置cur 上的木棍粘贴在第i根长木棍上 
	for(int i=0; i<m; i++){
		long_sticks[i] += sticks[cur];			//长木棍长度增加 
		f(cur+1, n, m, sticks, long_sticks, max(MAX, long_sticks[i]));		//处理下一位置的木棍 
		long_sticks[i] -= sticks[cur];			//恢复现场 
	}
}


int main(){	
	cin>>n>>m;

	for(int i=0; i<n; i++){
		cin >> sticks[i];
	} 

	f(0, n, m, sticks, long_sticks, MAX);
	
	cout<<ans<<endl;

	return 0; 
} 

方案2 递归 合并 (避免了大量不符题意的重复计算)

#include<iostream>
#include<cmath>

using namespace std;

int n;				//n个木棍 
int m;				//粘贴成m个长木棍
int sticks[7];		//sticks[i]: 第i+1个木棍长度 
int MIN;			//最短的长木棍长度 
int MAX; 			//最长的长木棍长度 
int ans=-1; 		//最小的差距


//函数功能:  有n个木棍,两两合并成m根, 求最小的差距 
void f(int n, int m, int sticks[]){
	//全部合并完 
	if(n == m){
		MAX = sticks[0];
		MIN = sticks[0];
		//找出最短的木棍 
		for(int i=1; i<m; i++){
			MIN = min(MIN, sticks[i]);
			MAX = max(MAX, sticks[i]);
		}
		
		//更新 最小的差距
		if(ans!=-1){
			ans = min(ans, (MAX-MIN));
		}else{
			ans = (MAX-MIN);
		}
		return ;
	}
	
	//没有合并完   将第i根木棍粘贴在第j根长木棍上 
	for(int i=0; i<n-1; i++){
		for(int j=i+1; j<n; j++){
			//记录i位置的木棍长度,便于恢复现场 
			int temp = sticks[i];
			
			//开始合并 
			sticks[j] += sticks[i];
			sticks[i] = sticks[n-1];
			
			f(n-1, m, sticks);
			
			//恢复现场 
			sticks[i] = temp;
			sticks[j] -= sticks[i];
		}
	}
}


int main(){	
	cin>>n>>m;

	for(int i=0; i<n; i++){
		cin >> sticks[i];
	} 

	f(n, m, sticks);
	
	cout<<ans<<endl;

	return 0; 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值