题目

题目描述

某农夫有一个养牛场,所有的牛圈都相邻的排成一排(共有S个牛圈),每个牛圈里面最多只圈养一头牛。有一天狂风卷积着乌云,电闪雷鸣,把牛圈的门给刮走了。幸运的是,有些牛因为放假,所以没在自己的牛圈里(只有C个牛圈里面有牛)。现在农夫需要去用木板将牛圈的门补好,为了快速修复,农夫可以用一块长的木板直接将相邻连续的几个牛圈一起钉好封闭。现在有一个木板供应商,他能够供应M块木板,每块木板的长度任意。农夫想让最终消耗的木板总长度最小,请编写一个程序计算。

数据范围

  1. 1 <= M <= 50
  2. 1 <= S <= 200
  3. 1 <= C <= S

样例输入

第一行输入M S C三个整数,接下来输入有牛的牛圈编号

4 50 18
3
4
6
8
14
15
16
17
21
25
26
27
30
31
40
41
42
43

样例输出

25

解题思路

我们可以证明将M块木板全部用上的时候可以让最终的木板总长度最少(这是比较明显的结论),利用贪心的思想,首先将编号进行排序,然后用一块木板从最小编号的牛圈开始,一直覆盖到最大编号的牛圈。之后我们需要找牛圈之间的间隔,每次都找最大的间隔,然后从中隔断,直到将一块木板拆成M块木板。

M > C时,我们可以进行特判,或者利用下面这种写法可以减少特判。

解题代码

/*
ID: yinzong2
PROG: barn1
LANG: C++11
*/
#define MARK
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm> using namespace std;
const int MAXN = 210; int m, s, c;
int stalls[MAXN]; bool vis[MAXN]; int main() {
#ifdef MARK
freopen("barn1.in", "r", stdin);
freopen("barn1.out", "w", stdout);
#endif // MARK
while(~scanf("%d%d%d", &m, &s, &c)) {
for(int i = 0; i < c; i++) {
scanf("%d", &stalls[i]);
vis[i] = false;
}
sort(stalls, stalls+c);
int _min = stalls[c-1] - stalls[0] + 1;
for(int i = 1; i < m; i++) {
int temp = 0;
int id = 0;
//找到当前最大的间隔
for(int j = 0; j < c-1; j++) {
if(!vis[j] && temp < (stalls[j+1]-stalls[j]-1)) {
temp = (stalls[j+1]-stalls[j]-1);
id = j;
}
}
vis[id] = true;
_min -= temp;
}
printf("%d\n", _min);
}
return 0;
}

解题思路(Type 2)

我们同样可以利用贪心的思想,将上面的思路进行反向操作,我们首先对于每个牛圈上都单独覆盖一块木板,那么此时就有C块木板。如果M > C我们就特判,否则,我们每次寻找牛圈之间的最小间隔,然后将两个牛圈之间用一块木板覆盖,这样我们可以减少一块木板,最终一直合并,减少到M块木板。

解题代码(Type 2)

/*
ID: yinzong2
PROG: barn1
LANG: C++11
*/
#define MARK
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm> using namespace std;
const int MAXN = 210; int m, s, c;
int stalls[MAXN];
bool vis[MAXN]; int main() {
#ifdef MARK
freopen("barn1.in", "r", stdin);
freopen("barn1.out", "w", stdout);
#endif // MARK
while(~scanf("%d%d%d", &m, &s, &c)) {
for(int i = 0; i < c; i++) {
scanf("%d", &stalls[i]);
vis[i] = false;
}
sort(stalls, stalls+c);
int ans = c;
int board = c;
while(board > m) {
int _min = MAXN;
int id = 0;
//寻找最小间隔
for(int i = 0; i < c-1; i++) {
if(!vis[i] && _min > (stalls[i+1]-stalls[i]-1)) {
_min = (stalls[i+1]-stalls[i]-1);
id = i;
}
}
vis[id] = true;
ans += _min;
board--;
}
printf("%d\n", ans);
}
return 0;
}

解题思路(Type 3)

我们还可以利用动态规划的思想来解决这个问题,我们首先定义一个函数dis(i, j),这个函数可以计算一块木板从第 i 个牛圈覆盖到第 j 个牛圈需要的木板长度。之后我们接着定义dp[i][j],它代表利用 i 块木板,一直覆盖到编号为 j 的牛圈所需要的最少的木板长度。所以我们最终要求的就是dp[M][C]

状态转移方程如下:

dp[i][j] = min(dp[i][j], min(dp[i-1][k]+dis(k+1, j), dp[i][k]+dis(k, j)-1)); (1 <= k < j)

解题代码(Type 3)

/*
ID: yinzong2
PROG: barn1
LANG: C++11
*/
#define MARK
#include<cstdio>
#include<cmath>
#include<algorithm> using namespace std;
const int MAXN = 210; int m, s, c; int stalls[MAXN]; int dp[55][MAXN]; int dis(int i, int j) {
return stalls[j]-stalls[i]+1;
} int main() {
#ifdef MARK
freopen("barn1.in", "r", stdin);
freopen("barn1.out", "w", stdout);
#endif // MARK
while(~scanf("%d%d%d", &m, &s, &c)) {
for(int i = 1; i <= c; i++) {
scanf("%d", &stalls[i]);
}
if(m > c) {
printf("%d\n", c);
continue;
}
sort(stalls+1, stalls+1+c);
for(int i = 1; i <= c; i++) {
dp[1][i] = dis(1, i);
}
for(int i = 2; i <= m; i++) {
for(int j = 1; j <= c; j++) {
dp[i][j] = MAXN;
for(int k = 1; k < j; k++) {
dp[i][j] = min(dp[i][j], min(dp[i-1][k]+dis(k+1, j), dp[i][k]+dis(k, j)-1));
}
}
}
printf("%d\n", dp[m][c]);
}
return 0;
}

USACO Section 1.3 Barn Repair 解题报告的更多相关文章

  1. USACO Section1.3 Barn Repair 解题报告

    barn1解题报告 —— icedream61 博客园(转载请注明出处)---------------------------------------------------------------- ...

  2. USACO Section 1.3 Prime Cryptarithm 解题报告

    题目 题目描述 牛式的定义,我们首先需要看下面这个算式结构: * * * x * * ------- * * * <-- partial product 1 * * * <-- parti ...

  3. USACO Section 1.4 Arithmetic Progressions 解题报告

    题目 题目描述 现在给你一个数集,里面的数字都是由p^2+q^2这种形式构成的0 <= p,q <= M,我现在需要你在其中找出一个长为N的等差数列,数列中的第一个数字为a,公差为b,当你 ...

  4. USACO Section 1.3 Combination Lock 解题报告

    题目 题目描述 农夫John的牛从农场逃脱出去了,所以他决定用一个密码锁来把农场的门锁起来,这个密码锁有三个表盘,每个表盘都是环形的,而且上面刻有1~N,现在John设了一个开锁密码,而且这个锁的设计 ...

  5. USACO Section 1.3 Mixing Milk 解题报告

    题目 题目描述 Merry Milk Makers 公司的业务是销售牛奶.它从农夫那里收购N单位的牛奶,然后销售出去.现在有M个农夫,每个农夫都存有一定量的牛奶,而且每个农夫都会有自己的定价.假设所有 ...

  6. USACO Section 1.2 Dual Palindromes 解题报告

    题目 题目描述 有一些数(如 21),在十进制时不是回文数,但在其它进制(如二进制时为 10101)时就是回文数. 编一个程序,从文件读入两个十进制数N.S.然后找出前 N 个满足大于 S 且在两种以 ...

  7. USACO Section 1.2 Palindromic Squares 解题报告

    题目 题目描述 输入一个基数B,现在要从1到300之间找出一些符合要求的数字N.如果N的平方转换成B进制数之后是一个回文串,那么N就符合要求.我们将N转换成B进制数输出,然后再将N的平方转换成B进制数 ...

  8. USACO Section 1.2 Milking Cows 解题报告

    题目 题目描述 有3个农夫每天早上五点钟便起床去挤牛奶,现在第一个农夫挤牛奶的时刻为300(五点钟之后的第300个分钟开始),1000的时候结束.第二个农夫从700开始,1200结束.最后一个农夫从1 ...

  9. USACO Section 1.1 Broken Necklace 解题报告

    题目 题目描述 有一串项链,它是由红蓝白三种颜色的珠子组成的,b代表蓝色,w代表白色,r代表红色,当它完整的时候是一个闭合的环形.现在它在某一个节点断裂了,之前的环形也随之变成了直线形.从两端开始收集 ...

随机推荐

  1. HDU1236:排名

    Problem Description 今天的上机考试虽然有实时的Ranklist,但上面的排名只是根据完成的题数排序,没有考虑  每题的分值,所以并不是最后的排名.给定录取分数线,请你写程序找出最后 ...

  2. 超赞!聊聊WEB APP、HYBRID APP与NATIVE APP的设计差异

    编者按:这3类主流应用你都了解吗?设计师除了要有视觉功夫,对不同形式的APP也应当了然于胸,今天百度的同学写了一篇非常全面的总结,帮你迅速搞定3类主流APP的设计方法,附带一大波避雷针,带你巧妙跳过A ...

  3. PureMVC 框架总结收录

    PureMVC框架的目标很明确,就是把程序分为低耦合的三层:Model.View和Controller. 通过使用PureMVC后,我们的代码将集中分为以下几个部分:Façade.Command.Me ...

  4. ios layer 动画

    #import "ViewController.h" @interface ViewController (){    CALayer *_l1;//定义能够全局使用    CAL ...

  5. NSArray的排序问题

    1.关于NSArray的排序问题,首先想到的是不是冒泡排序,插入排序....... oc中的NSArray有一种更简单的方式: 例如: NSArray *stringArray=[NSArray ar ...

  6. linux文件权限赋值

    1修改权限     命令:chmod (change mode)     功能:改变文件的读写和执行权限.有符号法和八进制数字法.     选项:(1)符号法:   命令格式:chmod {u|g|o ...

  7. CASE WHEN的两种格式

    CASE WHEN的两种格式 1.简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END 2.Case搜索函数 CASE ...

  8. mysql 不能插入中文

    三.#vim /etc/mysql/my.cnf .(5.5以前系统)在[client]下面加入 default-character-set=utf8 在[mysqld]下面加入default-cha ...

  9. mysql的登录和备份

    mysql -h xxx.xxx.xxx.xxx -u root -p -h 指出服务器名 若是localhost则是指本机 -u 指出用户名 root是默认的最高权限用户名 -p指出密码 不填就指密 ...

  10. bash和sh区别

    在一般的linux系统当中(如redhat),使用sh调用执行脚本相当于打开了bash的POSIX标准模式(等效于bash的 --posix 参数),一般的,sh是bash的“子集”,不是子集的部分. ...