USACO 1.4.2 修理牛棚

1.4.2 修理牛棚

题目考查

贪心算法, 思维考察

解题思路

本题相较上题而言, 思维难度很明显提升了. 这里给出两种供参考的解法

解法一: 扩增法

首先如果木板的数量大于牛的总数, 答案直接就是牛的总数了.

否则, 我们一定会有一些木板覆盖空牛棚, 我们想让木板总长度最小, 就相当于覆盖尽可能少的空牛棚.

假设牛棚编号从左到右依次为1~S, 我们把所有牛所在位置按编号从小到大排序, 记录在**a[]**中.
很显然, 覆盖[1, a[1])区间的空牛棚没有意义, (a[c], S]区间同理.

我们可以这样做: 记录a[i+1]到a[i]之间的空牛棚数量gapi = a[i+1] - a[i] - 1. 假设我们给每个有牛的牛棚都盖上一块长度为1板, 则会有c - 1个gap出现. 但是我们只有m块板, 只允许有m - 1个gap出现. 因此我们需要额外覆盖(c - 1) - (m - 1)个gap, 因此我们贪心选取c - m个较小的gap即可.


解法二: 删减法

PS: 本解法的变量命名同解法一.

我们不妨假设[a[1], a[c]]区间用一块木板覆盖了, 但实际上我们可以用m块, 我们可以想象成把一块木板分成了m块, 相当于我们可以删除m - 1个gap. 因此我们贪心删除最大的m - 1个gap即可.

需要注意的是, 我们一共只有c - 1个gap, 因此要么直接判断掉 m >= c的情况, 否则应注意次数不应超过c - 1次.

题目细节

  1. 当涉及到区间统计时, 我们要定义好变量的含义, 并注意是否需要±1.

AC代码

/* 解法一: 扩增法 */
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 210;
int a[N];
int main()
{
	int m, s, c; cin >> m >> s >> c;
	
	rep(i, c) scanf("%d", &a[i]);
	sort(a + 1, a + 1 + c);

	vector<int> gap;
	rep(i, c - 1) gap.push_back(a[i + 1] - a[i] - 1);
	sort(gap.begin(), gap.end());

	int res = c;
	rep(i, c - m) res += gap[i - 1];
	cout << res << endl;
	
	return 0;
}



/* 解法二: 删减法 */
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 210;
int a[N];
int main()
{
	int m, s, c; cin >> m >> s >> c;

	rep(i, c) scanf("%d", &a[i]);
	sort(a + 1, a + 1 + c);

	priority_queue<int> q;
	rep(i, c - 1) q.push(a[i + 1] - a[i] - 1);

	int res = a[c] - a[1] + 1;
	rep(i, m - 1) {
		res -= q.top(), q.pop();
		if (q.empty()) break;
	}
	cout << res << endl;

	return 0;
}

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥Fau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值