您的位置:首页 > 其它

POJ1191 棋盘分割(DP)

2016-03-11 17:22 435 查看
化简一下那个方差得到:$$\sqrt\frac{(\Sigma_{i=1}^nx_i)-n\bar x^2}{n}$$

除了$\Sigma_{i=1}^nx_i$这部分未知,其余已知,而那部分显然越大越好,很容易用DP去转移求得。

dp
[x1][y1][x2][y2]表示当前要切的矩形是(x1,y1,x2,y2)且还需要切n刀得到的最大的那部分的值

通过横竖切来转移,用记忆化搜索很容易实现

WA了好多发,听说有精度问题,一直搞精度,原来一个地方是爆int了。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define INF (1<<29)
int d[16][8][8][8][8];
int a[8][8];
int calc(int x1,int y1,int x2,int y2){
int res=0;
for(int i=x1; i<=x2; ++i){
for(int j=y1; j<=y2; ++j) res+=a[i][j];
}
return res;
}
int dp(int k,int x1,int y1,int x2,int y2){
if(d[k][x1][y1][x2][y2]!=-1) return d[k][x1][y1][x2][y2];
if(k==0) return d[k][x1][y1][x2][y2]=calc(x1,y1,x2,y2)*calc(x1,y1,x2,y2);
int res=INF;
for(int i=x1; i<x2; ++i){
res=min(res,dp(k-1,x1,y1,i,y2)+calc(i+1,y1,x2,y2)*calc(i+1,y1,x2,y2));
res=min(res,dp(k-1,i+1,y1,x2,y2)+calc(x1,y1,i,y2)*calc(x1,y1,i,y2));
}
for(int i=y1; i<y2; ++i){
res=min(res,dp(k-1,x1,y1,x2,i)+calc(x1,i+1,x2,y2)*calc(x1,i+1,x2,y2));
res=min(res,dp(k-1,x1,i+1,x2,y2)+calc(x1,y1,x2,i)*calc(x1,y1,x2,i));
}
return d[k][x1][y1][x2][y2]=res;
}
int main(){
memset(d,-1,sizeof(d));
int n;
scanf("%d",&n);
int sum=0;
for(int i=0; i<8; ++i){
for(int j=0; j<8; ++j) scanf("%d",&a[i][j]),sum+=a[i][j];
}
double avg=sum*1.0/n;
double ans = sqrt(dp(n-1,0,0,7,7)*1.0/n-avg*avg);
printf("%.3f\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: