UVa714 例题8-10 抄书

原题链接: UVa-714

题目大意:

  现有k个抄写员,m本书,每本书有若干页,每个抄书员需要抄写连续的若干本书。现在要找出一种分配方法使得抄写页数最多的那个抄写的页数最少。(有点绕,可以自行参考原题或者紫书P244)

解题思路:

 博主一开始的思路是根据序列平均值来判断,后来感觉不是很正确,就直接参考了紫书上给的思路。大致思路就是设s(i)为每个序列的和(每个抄书员抄的页数),找到大于所有s(i)的最小值x。然后就可以根据这个x利用贪心算法得到结果。至于x的获得方法,就是利用二分法,利用P(x0)来判断x0与x的关系。具体细节参考代码。

代码:

//E8-10 UVa714 AC P244
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>

using namespace std;

void print(long long mx);
long long find(int maxp, long long sum);
int p(int num);

const int MAXN = 500 + 5;

int arr[MAXN], m, k, n;

int main()
{
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	cin >> n;
	while (n--) {
		cin >> m >> k;
		long long sum = 0;
		int maxp = 0;
		for (int i = 0; i < m; i++) { //输入过程中获取总和及最大值 
			cin >> arr[i];
			sum += arr[i];
			maxp = max(maxp, arr[i]);
		}
		print(find(maxp, sum));
	}
	return 0;
}

void print(long long mx)//打印 
{
	int last[MAXN], remain = k;
	long long sum = 0;
	memset(last, 0, sizeof(last));
	for (int i = m - 1; i >= 0; i--) {//逆序找到每个断点处 
		if (sum + arr[i] > mx || i + 1 < remain) {
			last[i] = 1; remain--; sum = 0;
		}
		sum += arr[i];
	}
	for (int i = 0; i < m - 1; i++) {//输出 
		cout << arr[i] << " ";
		if (last[i]) cout << "/ ";
	}
	cout << arr[m - 1] << endl;
}

long long find(int maxp, long long sum)//找到使得大于等于所有s(i)且最小的值x 
{
	long long mx = sum, mn = maxp;
	while (mn < mx) {// 利用二分法找到x 
		long long mid = (mx + mn) / 2;
		if (p(mid) <= 0) mx = mid;// x <= mid,向下缩短范围 
		else mn = mid + 1;//x > mid,向上缩短范围  
	}
	return mn;
}
//比价使得s(i)均不超过的x与num的关系
//x > num 返回正数,x < num返回负数 ,x=num返回0
int p(int num)
{
	long long sum = 0;
	int cnt = 1;
	for (int i = 0; i < m; i++) {//计算以num为最大s(i)值的情况下,能分割为多少段 
		if (sum + arr[i] > num) {
			sum = 0; cnt++;
		}
		sum += arr[i];
	}
	return cnt - k;//比较cnt 与 k 
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值