Java教程

分治算法4 题目练习

本文主要是介绍分治算法4 题目练习,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
题目AB
名称网线主管月度开销
难度☆☆★★★☆☆★★★

A. 网线主管

内存限制:128 MiB 时间限制:1000 ms 标准输入输出
题目类型:传统 评测方式:文本比较

  • 题目描述

仙境的居民们决定举办一场程序设计区域赛。裁判委员会完全由自愿组成,他们承诺要组织一次史上最公正的比赛。他们决定将选手的电脑用星形拓扑结构连接在一起,即将它们全部连到一个单一的中心服务器。为了组织这个完全公正的比赛,裁判委员会主席提出要将所有选手的电脑等距离地围绕在服务器周围放置。

为购买网线,裁判委员会联系了当地的一个网络解决方案提供商,要求能够提供一定数量的等长网线。裁判委员会希望网线越长越好,这样选手们之间的距离可以尽可能远一些。

该公司的网线主管承接了这个任务。他知道库存中每条网线的长度(精确到厘米),并且只要告诉他所需的网线长度(精确到厘米),他都能够完成对网线的切割工作。但是,这次,所需的网线长度并不知道,这让网线主管不知所措。

你需要编写一个程序,帮助网线主管确定一个最长的网线长度,并且按此长度对库存中的网线进行切割,能够得到指定数量的网线。

  • 输入格式

第一行包含两个整数 N N N和 K K K,以单个空格隔开。 N ( 1 ≤ N ≤ 10000 ) N(1 \leq N \leq 10000) N(1≤N≤10000)是库存中的网线数, K ( 1 ≤ K ≤ 10000 ) K(1 \leq K \leq 10000) K(1≤K≤10000)是需要的网线数量。

接下来 N N N行,每行一个数,为库存中每条网线的长度(单位:米)。所有网线的长度至少 1 m 1m 1m,至多 100 k m 100km 100km。输入中的所有长度都精确到厘米,即保留到小数点后两位。

  • 输出格式

网线主管能够从库存的网线中切出指定数量的网线的最长长度(单位:米)。必须精确到厘米,即保留到小数点后两位。

若无法得到长度至少为 1 c m 1cm 1cm的指定数量的网线,则必须输出0.00(不包含引号)。

  • 样例

样例输入

4 11
8.02
7.43
4.57
5.39

样例输出

2.00
  • 提交

Link

题解部分

定义与输入

首先定义两个整数 n n n和 k k k,表示网线的数量和需要的截数。

再定义一个整型数组 a a a,表示每根网线的长度(不定义浮点数是因为避免精度误差)。

int n, k, a[10005];
double x;
scanf ("%d %d", &n, &k);	
for (int i = 1; i <= n; i ++) {
	scanf ("%lf", &x);
	a[i] = x * 100;
}

check 函数

定义整型函数check,统计截数。

: 计算截数时,暴力枚举每一段线可分出的截数,注意计算时用取整除

此处不放代码,请读者独立完成。

二分内容

1. l、r的初值

l l l的初值为 1 1 1(单位:cm), r r r的初值为所有长度的最大值。

2. while循环

  1. 条件: l < r

  2. m i d mid mid的赋值: mid = (l + r + 1) / 2;

  3. 改变 l ( r ) l(r) l(r)的条件:

if (check (mid) < k) {
	r = mid - 1;
} else {
	l = mid;
}

输出

check(l)>= k,即当前有解,则输出答案。

: l l l应除以 100.0 100.0 100.0。

否则,输出0.00

代码部分

: 该AC代码仅供参考,请勿抄袭!

#include <cstdio>
#include <algorithm>
using namespace std;

int n, k, l = 1, r = 0, a[10005], mid;
double x;

int check (int x) {
	int ans = ...(为了防止抄袭,这里不予显示);
	for (int i = 1; i <= n; i ++) {
		ans += a[i] / x;
	}
	return ans;
}

int main () {
	scanf ("%d %d", &n, &k);
	for (int i = 1; i <= n; i ++) {
		scanf ("%lf", &x);
		a[i] = x * 100;
		r = max (r, a[i]);
	}
	while (l < r) {
		mid = (l + r + 1) / 2;
		if (check (mid) < k) {
			r = mid - 1;
		} else {
			l = mid;
		}
	}
	if (check (l) >= k) {
		printf ("%.2lf", l / 100.0);
	} else {
		printf ("0.00");
	}
	return 0;
}

B. 月度开销

内存限制:128 MiB 时间限制:1000 ms 标准输入输出
题目类型:传统 评测方式:文本比较

  • 题目描述

农夫约翰是一个精明的会计师。他意识到自己可能没有足够的钱来维持农场的运转了。他计算出并记录下了接下来 N ( 1 ≤ N ≤ 100000 ) N(1 \leq N \leq 100000) N(1≤N≤100000) 天里每天需要的开销。

约翰打算为连续的 M ( 1 ≤ M ≤ N ) M(1 \leq M \leq N) M(1≤M≤N) 个财政周期创建预算案,他把一个财政周期命名为 f a j o fajo fajo月。每个 f a j o fajo fajo月包含一天或连续的多天,每天被恰好包含在一个 f a j o fajo fajo月里。

约翰的目标是合理安排每个 f a j o fajo fajo月包含的天数,使得开销最多的 f a j o fajo fajo月的开销尽可能少。

  • 输入格式

第一行包含两个整数 N , M N,M N,M,用单个空格隔开。

接下来 N N N行,每行包含一个 1 1 1到 10000 10000 10000之间的整数,按顺序给出接下来 N N N天里每天的开销。

  • 输出格式

一个整数,即最大月度开销的最小值。

  • 样例

样例输入

7 5
100
400
300
100
500
101
400

样例输出

500
  • 提交

Link

题解部分

定义与输入

首先定义两个整数 n n n和 m m m,表示天数和 f a j o fajo fajo月数。

再定义一个整型数组 a a a,表示每天的开销)。

int n, m, a[100005];
scanf ("%d %d", &n, &m);	
for (int i = 1; i <= n; i ++) {
	scanf ("%d", &a[i]);
}

check 函数

定义整型函数check,统计 f a j o fajo fajo月数。

  1. 定义前缀和变量 s u m sum sum和 f a j o fajo fajo月计数变量 a n s ans ans。

s u m sum sum赋初值 0 0 0, a n s ans ans赋初值1

  1. 暴力枚举每一天

如果没有达到每月开销,则 s u m sum sum累加 a i a_i ai​。

否则 f a j o fajo fajo月数量加 1 1 1, s u m sum sum置 0 0 0.

  1. 返回 a n s ans ans。

此处不放代码,请读者独立完成。

二分内容

1. l、r的初值

l l l的初值为所有开销的最大值, r r r的初值为所有开销之和。

2. while循环

  1. 条件: l < r

  2. m i d mid mid的赋值: mid = (l + r) / 2;

  3. 改变 l ( r ) l(r) l(r)的条件:

if (check (mid) > m) {
	l = mid + 1;
} else {
	r = mid;
}

输出

输出 m i d mid mid即可

代码部分

: 该AC代码仅供参考,请勿抄袭!

#include <cstdio>
#include <algorithm>
using namespace std;

int n, m, a[100005], l, r, maxn = 0, sum, mid;

int check (int x) {
	int sum, ans;
	sum = 0, ans = 1;
	for (int i = 1; i <= n; i ++) {
		if (...(为了防止抄袭,这里不予显示)) {
			ans ++;
			sum = a[i];
		} else {
			sum += a[i];
		}
	}
	return ans;
}

int main () {
	scanf ("%d %d", &n, &m);
	for (int i = 1; i <= n; i ++) {
		scanf ("%d", &a[i]);
		maxn = max (a[i], maxn);
		sum += a[i];
	}
	l = maxn, r = sum;
	while (l < r) {
		mid = (l + r) / 2;
		if (check (mid) > m) {
			l = mid + 1;
		} else {
			r = mid;
		}
	}
	printf ("%d", ...(为了防止抄袭,这里不予显示));
	return 0;
}
这篇关于分治算法4 题目练习的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!