您的位置:首页 > 其它

bzoj 1575: [Usaco2009 Jan]气象牛Baric 动态规划

2016-10-15 16:28 351 查看
Description

为了研究农场的气候,Betsy帮助农夫John做了N(1 <= N <= 100)次气压测量并按顺序记录了结果M_1…M_N(1 <= M_i <= 1,000,000). Betsy想找出一部分测量结果来总结整天的气压分布. 她想用K(1 <= K <= N)个数s_j (1 <= s_1 < s_2 < … < s_K <= N)来概括所有测量结果. 她想限制如下的误差: 对于任何测量结果子集,每一个非此子集中的结果都会产生误差.总误差是所有测量结果的误差之和.更明确第说, 对于每一个和所有s_j都不同的i: * 如果 i 小于 s_1, 误差是: 2 * | M_i - M_(s_1) | * 如果i在s_j和s_(j+1)之间,误差是: | 2 * M_i - Sum(s_j, s_(j+1)) | 注:Sum(x, y) = M_x + M_y; (M_x 和 M_y 之和) * 如果i大于s_K,误差为: 2 * | M_i - M_(s_K) | Besty给了最大允许的误差E (1 <= E <= 1,000,000),找出最小的一部分结果史得误差最多为E.

Input

第一行: 两个空格分离的数: N 和 E

第2..N+1行: 第i+1行包含一次测量记录:M_i

Output

第一行: 两个空格分开的数: 最少能达到误差小于等于E的测量数目和使用那个测量数目能达到的最小误差.

Sample Input

4 20

10

3

20

40

输入解释:

Bessie做了4次记录,分别为10,3,20,和40.最大允许误差是20.

Sample Output

2 17

HINT

选择第二和第四次测量结果能达到最小误差17. 第一次结果的误差是2*|10-3| = 14; 第三次结果的误差是|2*20 - (3+40)|=3.

分析:设f[i,j,k]表示前i个测量结果选了j个且最后一个为k时的最小误差。

我们预处理出s[i,j]表示若i和j都选那么m[i+1…j-1]对答案的贡献是多少。

beg[i]表示如果以i作为第一个选的话那么m[1…i-1]对答案的贡献是多少。

end[i,j]表示如果以i作为最后一个选的且右边界为j时m[i+1…j]对答案的贡献。

那么很容易得出f[i,1,i]=beg[i]

接着分两种情况讨论:

若k比i小则f[i,j,k]=min(f[i-1,j-1,l]+s[l,k]-end[l,k-1],f[i,j,k]);

否则f[i,j,k]=f[i-1,j,k]+2*abs(m[i]-m[k]);

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;

int n,E,f[105][105][105],s[105][105],a[105],beg[105],end[105][105];

int main()
{
scanf("%d%d",&n,&E);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=n;i++)
for (int j=i+2;j<=n;j++)
for (int k=i+1;k<=j-1;k++)
s[i][j]+=abs(2*a[k]-a[i]-a[j]);
for (int i=2;i<=n;i++)
for (int j=1;j<i;j++)
beg[i]+=2*abs(a[i]-a[j]);
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++)
end[i][j]=end[i][j-1]+2*abs(a[i]-a[j]);
memset(f,inf,sizeof(f));
f[1][1][1]=0;
f[1][0][0]=0;
for (int i=2;i<=n;i++)
{
for (int j=1;j<=i;j++)
for (int k=j;k<=i;k++)
if (k<i) f[i][j][k]=f[i-1][j][k]+2*abs(a[i]-a[k]);
else
{
f[i][j][k]=inf;
for (int l=max(j-1,1);l<i;l++)
f[i][j][k]=min(f[i-1][j-1][l]+s[l][k]-end[l][k-1],f[i][j][k]);
}
f[i][1][i]=beg[i];
}
int ans=inf,ans1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
if (f
[i][j]<=E) ans=min(ans,f
[i][j]);
if (ans<=E)
{
ans1=i;
break;
}
}
printf("%d %d",ans1,ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: