您的位置:首页 > 其它

poj 1191 棋盘分割

2014-03-08 15:52 344 查看
题目意思,中文不解释:

——————————————

分割线

——————————————

根据题目的公式可得到,很多东东。

σ=sqrt(((x1-x)^2+(x2-x)^2+...+(xn-x)^2)/n),其中x为x1..xn的平均数.
所以σ^2=((x1-x)^2+(x2-x)^2+...+(xn-x)^2)/n
即:n*σ^2=(x1-x)^2+(x2-x)^2+...+(xn-x)^2
                =x1^2-2x*x1+x^2+x2^2-2x*x2+x^2+...+xn^2-2x*xn+x^2
                =x1^2+x2^2+...+xn^2-2x(x1+x2+...+xn)+n*x^2
                =x1^2+x2^2+...+xn^2-2x*n*x+n*x^2
                =x1^2+x2^2+...+xn^2-n*x^2
那么得到:

        n*σ^2+n*x^2=x1^2+x2^2+...+xn^2.

题目要求σ最小,而x为常数,其实质就是把棋盘分为每部分和分别为x1..xn的n部分,使得这n部分的平方和最小.既然要求被化简了,我们的任务也就很明确了.本题可以用一个记忆化搜索。用一个数组dp
[x1][y1][x2][y2]来记录结果:

具体见代码:

#include<iostream>
#include<fstream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<sstream>
#include<cassert>
using namespace std;
#define LL __int64
#define min(a,b) a<b?a:b
#define inf 99999999

int a[15][15];
int n;
int temp;
int dp[16][15][19][19][19];

//根据数组a[][]存储的值求任意矩形的和
int getsum(int x1,int y1,int x2,int y2) {
return a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1];
}

int getcat(int N,int x1,int y1,int x2,int y2) {

if(dp
[x1][y1][x2][y2]!=-1) return dp
[x1][y1][x2][y2];
//已经求过就可以直接返回了,避免重复运算导致超时(类似CF汉罗塔的一道题目,当时没这个优化超时)
int s1,s2;
//N==1说明切割了n-1次,最后剩下的一块矩形求出其和的平方直接返回
if(N==1) {
s1=getsum(x1,y1,x2,y2);
dp
[x1][y1][x2][y2]=s1*s1;
return s1*s1;
}

int mi=inf;
int temp1;
//水平方向切
for(int x=x1; x<x2; x++) {
s1=getsum(x1,y1,x,y2);
s2=getsum(x+1,y1,x2,y2);
//横向将当前的矩形切割为两块后,继续将两块进行切割,最后返回时,选取得到的值较小的
temp1=min(getcat(N-1,x1,y1,x,y2)+s2*s2,getcat(N-1,x+1,y1,x2,y2)+s1*s1);
mi=min(mi,temp1);

}
//竖直方向切
int temp2;
for(int y=y1; y<y2; y++) {
s1=getsum(x1,y1,x2,y);
s2=getsum(x1,y+1,x2,y2);
temp1=min(getcat(N-1,x1,y1,x2,y)+s2*s2,getcat(N-1,x1,y+1,x2,y2)+s1*s1);
mi=min(mi,temp1);

}
dp
[x1][y1][x2][y2]=mi;
return mi;
// mi记录横向和纵向切割后,值较小的
}

int main() {
while(cin>>n) {
int sum=0;
memset(a,0,sizeof(a));
memset(dp,-1,sizeof(dp));
for(int i=1; i<=8; i++) {
for(int j=1; j<=8; j++) {
scanf("%d",&temp);
a[i][j]=temp+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
sum+=temp;
}
}

double x=(sum*1.0)/n;
int T=getcat(n,1,1,8,8);
//根据公式可得到结果
double ans=sqrt(abs((T*1.0)/n-x*x));
printf("%.3f\n",ans);
}

return 0;
}

/*

3
1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 3

*/

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