枚举算法——绳子切割

问题描述:
  有n条绳子,它们的长度为Li(Li<=1000),如果从它们中切割出k条长度相同的绳子的话,这k条绳子每条最长能有多长,答案保留到小数点后两位。
输入描述:
第一行输入两个整数n,k。表示有n条绳子和要切割出k条长度相同的绳子。
第二行输入n个数表示每条绳子的长度。
输出描述:
输出一个数,即k条绳子最长能有多长。保留到小数点后两位。
输入:
4 11
8.02 7.43 4.57 5.39
输出:
2.00
思路1:(暴力枚举)
枚举对象是绳子长度,从0.01到绳子的最大长度,步长为0.01(题目要求保留到小数点后两位)。对于枚举的每个长度,我们要验证在该长度下是否能切割出k条绳子,找出一个能切割且最长的长度,即满足Cnt(i)>=k的最大 i 。Cnt(i) 返回的是切割长度为 i 时可以切割绳子的条数。

for(double i=0.01;i<=Max;i+=0.01)
{
	if(Cnt(i)>=k)
		ans=i;  //ans更新为更大的 i
	else   //Cnt(i) < k 说明长度已经过大了
		break;
}

思路二:(二分枚举)
我们需要的是满足Cnt(i) >=k 的最大的 i。假设我们枚举的区间是 [L,R],存在Mid=(L+R)/2。
如果对于Cnt(Mid)>=k,说明Mid长度小了(或刚好合适),那么对于所有[L,Mid) 长度都小了,可以舍去[L,Mid),将L更新为Mid,新的枚举范围为[Mid,R]。
如果对于Cnt(Mid)<k,说明Mid长度大了,那么对于所有[Mid,R]长度都大了,可以舍去[Mid,R],将R更新为Mid-0.01。新的枚举范围更新为[L,Mid-0.01]。
最后的L即为k条绳子最大长度。

while(R-L>0.001)
{
	double Mid=(L+R)/2;
	if(Cnt(Mid)>=k)
		L=Mid;
	else
		R=Mid-0.01;
}

二分枚举完整代码:

#include<stdio.h>
double Len[100];
int n,k;
int Cnt(double mid)
{
	int cnt=0;
	for(int i=0;i<n;i++)
		cnt+=(int)(Len[i]/mid);
	return cnt;
}
int main()
{
	scanf("%d%d",&n,&k);
	double Max=-1;
	for(int i=0;i<n;i++)
	{
		scanf("%lf",&Len[i]);
		Max=Max>Len[i]? Max:Len[i];
	}
	double L=0,R=Max;
	while(R-L>0.001)
	{
		double Mid=(L+R)/2;
		if(Cnt(Mid)>=k)
			L=Mid;
		else
			R=Mid-0.01;
	}
	printf("%.2f\n",L);
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值