您的位置:首页 > 运维架构

[NOI1999][openjudge]棋盘分割(数学相关+dp)

2016-10-26 17:40 323 查看

题目描述

传送门

题解

NOI1999的dp都好厉害呀= =

一定要认真读题!

先看这个均方差的式子,可以进行化简:

δ=∑ni=1(xi−x¯)2n−−−−−−−−−√

δ2=1n∑ni=1(xi−x¯)2

=1n∑ni=1(x2i−2xix¯+x¯2)

=1n∑ni=1x2i−1n∑ni=12xix¯+1n∑ni=1x¯2

=1n∑ni=1x2i−2x¯1n∑ni=1xi+1n∑ni=1x¯2

=1n∑ni=1x2i−x¯2

显然1n和x¯2都是定值,那么我们的任务是求∑ni=1x2i的最小值。

设f(i,a,b,c,d)表示切第i刀,剩余的矩形左上角和右下角的坐标是(a,b)和(c,d),除了剩余部分其它部分的xi平方和的最小值。那么f(i)可以向f(i+1)转移,只需要暴力枚举第i+1刀从哪里切了一刀即可。

矩阵前缀和搞的时候细节比较多,一定要细心。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 20

int n;
double x,y,Min,ans;
double v

,s

,f
[10][10][10][10];

int main()
{
scanf("%d",&n);
for (int i=1;i<=8;++i)
for (int j=1;j<=8;++j) scanf("%lf",&v[i][j]);
for (int i=1;i<=8;++i)
for (int j=1;j<=8;++j)
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+v[i][j];

memset(f,127,sizeof(f));Min=f[0][0][0][0][0];
for (int a=1;a<8;++a)
{
x=s[8][8]-s[8][a];
f[1][1][1][8][a]=x*x;
x=s[8][a];
f[1][1][a+1][8][8]=x*x;

x=s[a][8];
f[1][a+1][1][8][8]=x*x;
x=s[8][8]-s[a][8];
f[1][1][1][a][8]=x*x;
}
for (int i=1;i<n-1;++i)
for (int a=1;a<=8;++a)
for (int b=1;b<=8;++b)
for (int c=a;c<=8;++c)
for (int d=b;d<=8;++d)
{
x=f[i][a][b][c][d];
for (int e=a;e<c;++e)
{
y=s[c][d]-s[c][b-1]-s[e][d]+s[e][b-1];
f[i+1][a][b][e][d]=min(f[i+1][a][b][e][d],x+y*y);
y=s[e][d]-s[e][b-1]-s[a-1][d]+s[a-1][b-1];
f[i+1][e+1][b][c][d]=min(f[i+1][e+1][b][c][d],x+y*y);
}
for (int e=b;e<d;++e)
{
y=s[c][d]-s[c][e]-s[a-1][d]+s[a-1][e];
f[i+1][a][b][c][e]=min(f[i+1][a][b][c][e],x+y*y);
y=s[c][e]-s[c][b-1]-s[a-1][e]+s[a-1][b-1];
f[i+1][a][e+1][c][d]=min(f[i+1][a][e+1][c][d],x+y*y);
}
}
for (int a=1;a<=8;++a)
for (int b=1;b<=8;++b)
for (int c=a;c<=8;++c)
for (int d=b;d<=8;++d)
{
x=f[n-1][a][b][c][d];
y=s[c][d]-s[c][b-1]-s[a-1][d]+s[a-1][b-1];
Min=min(Min,x+y*y);
}
double t=Min/(n+0.0);
ans=Min/(n+0.0)-(s[8][8]/(n+0.0))*(s[8][8]/(n+0.0));
ans=sqrt(ans);
printf("%0.3lf\n",ans);
}


总结

①认真读题!认真读题!认真读题!

②抵制手残!抵制手残!抵制手残!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: