小韦老师@神犇营-USACO1.3.2-修理牛棚_c++ usaco 修理牛棚-程序员宅基地

技术标签: 修理牛棚  C++  贪心算法  动态规划  USACO  小韦同学@题解:神犇营  

小韦老师@神犇营-USACO1.3.2-修理牛棚

题目:

描述

题意:
在一个夜黑风高,下着暴风雨的夜晚,农民约翰的牛棚的屋顶、门被吹飞了。 好在许多牛正在度假,所以牛棚没有住满。 这些牛在互相挨着的排成一排的牛棚中过夜。 有些牛棚里有牛,有些没有。 所有的牛棚有相同的宽度。 自门遗失以后,农民约翰必须尽快在牛棚之前竖立起新的木板。 他的新木材供应商将会供应他任何他想要的长度,但是供应商只能提供有限数目的木板。 农民约翰想将他购买的木板总长度减到最少。
给出:可能买到的木板最大的数目 M (1 <= M <= 50);牛棚的总数 S (1 <= S <= 200); 牛棚里牛的总数 C (1 <= C <= S); 和牛所在的牛棚的编号 stall_number (1 <= stall_number <= S), 计算拦住所有有牛的牛棚所需木板的最小总长度。
输出所需木板的最小总长度作为答案。
注意:
牛棚的长度为被拦住的牛棚总数量。

输入

第 1 行: M , S 和 C (每两个数之间用一个空格分开) 。
第 2 到 C+1行: 每行包含一个整数,表示牛所占的牛棚的编号。

输出

单独的一行包含一个整数表示被拦住的牛棚总数量。

输入样例1
4 50 18
3
4
6
8
14
15
16
17
21
25
26
27
30
31
40
41
42
43
输出样例1

25

题解:

破题:

总共有 M 块木板,有 C 头牛,在把所有牛都拦住的前提下,求被拦住的牛棚总数量的最小值。

思路:

方法一:贪心算法
用变量 ans 表示拦住的牛棚数量的最小值,并且将 ans 初始化为 0。
(1)计算有牛的牛棚连通块的块数 num,若 num ≤ M,则转到(2),否则转到(3)。
(2)num ≤ M 说明木板数比牛的数量多,则 ans = C,因为至少要保证每头牛都要被拦住。
(3)如果 M < C,则首先要将牛所在的牛棚号进行升序排列,求出每一个间隔的大小,存在一个数组 mid 中,将间隔的数组进行升序排列,初始化 index 为 0,转到(4)。
(4)如果 num > M,则循环执行 ans += mid[index++],num–,否则结束循环。
(5)输出 ans 即为所求。
方法二:动态规划
用数组 stall 来存储有牛的牛棚编号,需要升序排列。
用 f[i][j] 来作为描述信息,表示前 i 块木板挡住前 j 个有牛的牛棚的最小长度(这里注意是有牛棚的牛棚,j 不是牛棚编号,而是 stall 数组的编号)。
(1)当 j = 1 时,f[i][j] = 1
【注】
当 j = 1,说明只有一个牛棚里有牛,则只需要挡住这一个有牛的牛棚就可以,所以最小长度为 1。
(2)当 i = 1 时,f[i][j] = stall[j] - stall[1] + 1
【注】
当 i = 1 时,说明只有一块木板,则需要挡住的最小长度是从第 1 个有牛的牛棚到第 j 个有牛的牛棚。
(3)当 i != 1 && j != 1 时,f[i][j] = min(f[i-1][j-1] + 1, f[i][j - 1] + stall[j] - stall[j - 1])
【注】
f[i - 1][j - 1] 表示的是前 i - 1 个木板挡住了前 j - 1 个有牛的牛棚的最小长度,所以第 i 块木板就给第 j 个有牛的牛棚,所以加一即可。
f[i][j-1] 表示前 i 个木板挡住了前 j - 1 个有牛的牛棚的最小总长度,现在已经没有木板了,只能把挡住第 j - 1 的那个木板延伸到第 j 个有牛的牛棚,所以增加的长度为 stall[j] - stall[j - 1]

完整代码:

方法一:贪心算法

#include<bits/stdc++.h>

using namespace std;

const int N = 210;
int m;  // 最大木板数
int s;  // 牛棚总数
int c;  // 牛的总数
int stall[N];  // 有牛的牛棚编号
int mid[N];  // 有牛的牛棚之间的间隔

int block() {
	int num = 1;  // 记得要初始化为 1
	for (int i = 0; i < c - 1; i++) {
		if (stall[i + 1] != stall[i] + 1) {
			num++;
		}
	}
	return num;  // 记得返回
}

void cal_mid() {
	int index = 0;  // 数组下标
	for (int i = 1; i < c; i++) {
		// m 为间隔
		int m = stall[i] - stall[i - 1] - 1;
		// 若有间隔,则将间隔存到数组 mid 中
		if (m) mid[index++] = m;
	}
	sort(mid, mid + index);  // 记得升序排序
}

int main() {
    
	cin >> m >> s >> c;
	for (int i = 0;  i < c; i++) {
		cin >> stall[i];
	}
	sort(stall, stall + c);
	int num = block();
	int ans = 0;  // 被拦住的牛棚总数量的最小值
	if (num <= m) ans = c;
	else {
		cal_mid();
		int index = 0;  // 数组下标
		while (num > m) {
			ans += mid[index++];  // 依次加上间隔数
			num--;  // 连通的块数减一
		}
		ans += c;
	}
	cout << ans;
	
	return 0;
}

方法二:动态规划

#include <bits/stdc++.h>

using namespace std;

const int N = 210;
int m;  // 最大木板数
int s;  // 牛棚总数
int c;  // 牛的总数
int stall[N];  // 有牛的牛棚编号
int f[N][N];

int main() {
    
	cin >> m >> s >> c;
	for (int i = 1;  i <= c; i++) {
		cin >> stall[i];
	}
	// 将有牛的牛棚升序排列,记得要加 1
	sort(stall + 1, stall + c + 1);
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= c; j++) {
			if (j == 1) {  // 只有一个牛棚有牛
				f[i][j] = 1;
			} else if (i == 1) {  // 只有一块木板
				f[i][j] = stall[j] - stall[1] + 1;
			} else {
				f[i][j] = min(f[i - 1][j - 1] + 1, f[i][j - 1] + stall[j] - stall[j - 1]);
			}
		}
	}
	// 输出结果
	cout << f[m][c];
	
	return 0;
}            
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_31790997/article/details/92082932

智能推荐

windows 11系统安装_win11安装程序-程序员宅基地

文章浏览阅读1.2w次,点赞17次,收藏166次。1、制作好U盘之后,把U盘接上需要安装系统的机器,台式机或一体机可在开机按F12键调出引导菜单,台式机安装的时候建议断开网线,笔记本开机按F12或者Fn+F12键调出引导菜单。2、出现菜单选项后,选择“Boot Menu”启动菜单回车,选择USB项回车启动开始安装系统。6、输入PIN密码,(如果主机支持生物识别设备,也可在输入PIN后,继续录入指纹或人脸)4、插入准备好的U盘,如果没有显示,点击刷新驱动器列表,点击下一步。7、选择同步设备,如不想同步,选择设置为新设备。3、选择制作U盘,点击下一步,_win11安装程序

【深度学习】归一化_深度学习 那些情况 要做 归一化-程序员宅基地

文章浏览阅读1.8w次,点赞8次,收藏11次。​ 以前在神经网络训练中,只是对输入层数据进行归一化处理,却没有在中间层进行归一化处理。要知道,虽然我们对输入数据进行了归一化处理,但是输入数据经过 $ \sigma(WX+b) $ 这样的矩阵乘法以及非线性运算之后,其数据分布很可能被改变,而随着深度网络的多层运算之后,数据分布的变化将越来越大。如果我们能在网络的中间也进行归一化处理,是否对网络的训练起到改进作用呢?答案是肯定的。​ 这种在神经网络中间层也进行归一化处理,使训练效果更好的方法,就是批归一化Batch Normalization(BN)。_深度学习 那些情况 要做 归一化

微信小程序支付接口实现(java后台)_小程序后台java支付接口-程序员宅基地

文章浏览阅读1.2w次,点赞12次,收藏101次。#(Notice:以下所有经验也是我根据网上的经验整理的,如有侵权可以联系我删除,QQ 654303408。 有问题讨论也可联系我,QQ同上。)#(Tips:我是第一次开发,一个刚毕业的java工程师,我觉得我并非天赋异禀,我能学会,相信聪敏的你,一定可以)#(PS:目前微信拥有无可撼动的人口基数,越来越多的项目开发是基于微信小程序,或者APP。但是支付方式无非两种,一种是支付宝,一种是微信支..._小程序后台java支付接口

python web server_用Python建立最简单的web服务器-程序员宅基地

文章浏览阅读27次。第一个python Web程序——简单的Web服务器。与其它Web后端语言不同,Python语言需要自己编写Web服务器。如果你使用一些现有的框架的话,可以省略这一步;如果你使用Python CGI编程的话,也可以省略这一步;用Python建立最简单的web服务器利用Python自带的包可以建立简单的web服务器。在DOS里cd到准备做服务器根目录的路径下,输入命令:python -m Web服务..._pyjwt webserver

【图像重建指标 Metrics】均方误差RMSE及平均绝对误差MAE的定义和区别_rmse与mae有换算公式吗-程序员宅基地

文章浏览阅读1.3w次,点赞3次,收藏23次。RMSE和MAE能很好的反应图像的重建结果与真实结果间的差异。_rmse与mae有换算公式吗

Kotlin Gradle Junit单元测试print输出控制台_gradle 打印日志 system. out.print-程序员宅基地

文章浏览阅读3.4k次。背景默认情况下,Gradle 单元测试,是无法使用 System.out.println 这样打印变量信息的,这会让我们debug变得非常麻烦。百度网上很多方案,,但都比较麻烦,也很容易踩坑,。换了个搜索姿势,google了下,原来方案如此简单。解决在你的模块下的build.gradle.kts添加如下的配置:tasks.withType<Test> { this.testLogging { this.showStandardStreams = true _gradle 打印日志 system. out.print

随便推点

sqlmap的使用--绕过--自带脚本tamper_sqlmap绕过脚本-程序员宅基地

文章浏览阅读2.2k次,点赞2次,收藏11次。sqlmap在默认的的情况下除了使用char()函数防止出现单引号,没有对注入的数据进行修改,还可以使用–tamper参数对数据做修改来绕过waf等设备。命令格式:sqlmap -u [url] --tamper [模块名]通过使用whereis sqlmap查看sqlmap安装路径,自带的脚本一般是在usr/share/sqlmap/tamper下,我的是1.6.3版本一共有66个自带脚本下边引一些常用的脚本:apostrophemask.py适用数据库:ALL作用_sqlmap绕过脚本

换行分隔符_分隔符 换行-程序员宅基地

文章浏览阅读1.7k次。windows:\r\nlinux:\rmac:\n_分隔符 换行

waves效果器_混音选择困难2,Waves均衡器全介绍与理论使用心得-程序员宅基地

文章浏览阅读4.2k次,点赞2次,收藏8次。喜欢「音乐杂谈」这个主题的朋友可以关注我的头条号,将会在不定期发表一些音乐理论以外的音乐话题的文章或者是音乐知识的干货 。(此文为混音师天职老师 发布于今日头条的原创文章,转载请告知并注明出处)通篇写作整理下来差不多花了7个小时,不管怎样,施舍点个赞吧。哈哈哈!继上一次「音乐杂谈41」混音选择困难第一期,给大家介绍了Waves全家桶的大部分压缩器之后,本篇,我们将来看看,Waves全家桶的大部分均..._waves功能详解

在Android中播放音频和视频_android 播放语言视频-程序员宅基地

文章浏览阅读2.8k次。Android媒体包提供了可管理各种媒体类型的类。这些类可提供用于执行音频和视频操作。除了基本操作之外,还可提供铃声管理、脸部识别以及音频路由控制。本文说明了音频和视频操作。本文简介媒体包提供了可管理各种媒体类型的类。这些类可提供用于执行音频和视频操作。除了基本操作之外,还可提供铃声管理、脸部识别以及音频路由控制。本文说明了音频和视频操作。范围:_android 播放语言视频

Sublime and Markdown-程序员宅基地

文章浏览阅读2.7k次。Sublime & Markdown文章目录Sublime & Markdown安装 Sublime设置 Sublime安装插件Package ControlMarkdownEditingMarkdown PreviewLiveReloadauto-saveOmniMarkupPreviewerEvernote插件&主题插入图片Ctrl+vHTML语法Markdown语法...

android uboot log,RK3288 Android 8.1系统uboot logo过渡到kernel logo会花一下-程序员宅基地

文章浏览阅读695次。在调试RK3288 Android 8.1系统遇到一个问题:开机启动uboot logo过渡到kernel log的过程中会花掉直到没有显示,再出现kernel logo。分析:打印串口log时发现,uboot阶段显示一切正常,进入kernel以后就开始花掉了然后变成没有显示了,感觉像是慢慢掉电了一样,再继续查看log发现如下打印:[ 0.363167] Registered fiq deb..._mtk 转屏后 logo uboot 转kernel 显示异常

推荐文章

热门文章

相关标签