UVA ~ 714 ~ Copying Books(二分+最大值最小化)

题意:给你K本书分给M个人抄,这M个人抄书的速度相同,每个人抄的书的编号必须连续,问怎么划分可以最快的抄完这M本书?

思路:典型的最大值最小化的问题,二分答案,对于当前答案看能否分成M段或者小于M段,求一个满足要求的下界值。主要是判断函数怎么写?首先我们会进行一段一段的划分,因为题目中要求当剩余元素等于字典序最小,所以我们应该让后面的段尽量多,所以我们就从后面往前划分。划分时有三种情况

<1>未划分的段数等于未划分的元素个数,此时应该每个元素一段,证明当前值可行返回true

<2>当前段中的总值小于等于当前二分的答案M,我们就继续往这个段添加元素,如果大于我们就将i+1及其后面的元素划分为一段(因为是从后往前划分的)

<3>需要划分的段数大于M就证明当前值不可行返回false

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5e2 + 5;
long long k,M,a[MAXN],Max;
bool vis[MAXN];//标记在哪个数字后面划段 
bool check(long long m)
{
	memset(vis,0,sizeof(vis));
	long long sum = a[k - 1],group = 1;//sum用来计算当前段的和,group用来记录当前正在分第几段 
	for(int i = k - 2; i >= 0; i--)
	{
		if(a[i] > m) return false;//有元素的值大于m 
		if(i + 1 > M - group)//剩余的元素个数 > 剩余的组数 
		{
			sum += a[i];
			if(sum > m)
			{
				vis[i] = true;
				sum = a[i];
				group++;
				if(group > M) return false;
			}
		}
		else if(i + 1 == M - group)//剩余的元素个数 == 剩余的组数 
		{
			for(int j = i; j >= 0; j--)
			{
				if(a[j] > m) return false;//有元素的值大于m 
				vis[j] = true;
			}
			return true;
		}	
	}
	return true;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		Max = 0;//用来统计一个二分上限值 
		scanf("%lld%lld",&k,&M);
		for(int i = 0; i < k; i++) 
		{
			scanf("%lld",&a[i]);
			Max += a[i];
		}
		long long l = 0,r = Max,m = l + (r - l) / 2;
		while(l < r)
		{
			if(check(m) == false) l = m + 1;
			else r = m;
			m = l + (r - l) / 2;
		}
		check(m);
		for(int i = 0; i < k; i++)
		{
			printf("%lld",a[i]);
			if(i != k - 1) printf(" ");
			if(vis[i]) printf("/ ");
		}
		printf("\n");
	} 
	return 0;
}
/*
8
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100
4 2
1 2 4 8
6 2
1 2 4 8 4 2
6 2
1 2 3 3 2 1
2 2
10000000 10000000
6 3
1000000 1 1 1 1 1
6 6
6 5 4 3 2 1
*/




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值