维修栅栏(fence)

原题搁这

描述

小晶晶最近当上了农场主!不过,还没有来得及庆祝,一件棘手的问题就摆在了小晶晶的面前。农场的栅栏,由于年久失修,出现了多处破损。栅栏是由n块木板组成的,每块木板可能已经损坏也可能没有损坏。小晶晶知道,维修连续m个木板(这m个木板不一定都是损坏的)的费用是sqrt(m)。可是,怎样设计方案才能使总费用最低呢?小晶晶想请你帮帮忙。

输入

第一行包含一个整数n,表示栅栏的长度;

第二行包含n个由空格分开的整数(长整型范围内)。如果第i个数字是0,则表示第i块木板已经损坏,否则表示没有损坏。

输出

仅包含一个实数,表示最小维修费用;注意:答案精确到小数点后3位。

输入样例 1

9 0 –1 0 1 2 3 0 –2 0

输出样例 1

3.000

提示

30%的数据中,n≤20;

100%的数据中,n≤2500。

来源 聪明人的游戏


解决这道题

这道题我们很明显可以dpdp来解决。

So我们就要对这堆栅栏进行分类讨论, 假设我们修到了第i个帐篷,那么就有以下几种可能:

(1) 这个帐篷本来就是好的;

(2) 这个帐篷不是好的;

对于(1)来说,我们不用修,直接就是dp[i]=dp[i1];dp[i]=dp[i-1];

对于(2)来说,我们要修,怎么修——选最少的修。所以我们枚举一下

单独修

两个两个修

三个三个修

.............

全都一起修

So

f[i]=f[i1]+sqrt(1);f[i] = f[i-1]+sqrt(1);

f[i]=f[i2]+sqrt(2);f[i] = f[i-2]+sqrt(2);

f[i]=f[i3]+sqrt(3);f[i] = f[i-3]+sqrt(3);

.............

f[i]=f[0]+sqrt(i);f[i] = f[0]+sqrt(i);

选最小的就好了。

完整代码:

#include<bits/stdc++.h>
using namespace std;
int n,a[3000];
double dp[3000];
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++)
		dp[i]=2147483647;
	for(int i=1;i<=n;i++) {
		if(!a[i]) {
			for(int j=1;j<=i;j++)
				dp[i]=min(dp[i-j]+sqrt(j),dp[i]);
		}else 
			dp[i]=dp[i-1];
	}
	printf("%.3lf",dp[n]);
	return 0;
}
posted @ 2022-03-14 13:57  cjrqwq  阅读(40)  评论(0)    收藏  举报  来源