POJ1191 棋盘分割(DP)

化简一下那个方差得到:$$\sqrt\frac{(\Sigma_{i=1}^nx_i)-n\bar x^2}{n}$$

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

  • dp[n][x1][y1][x2][y2]表示当前要切的矩形是(x1,y1,x2,y2)且还需要切n刀得到的最大的那部分的值
  • 通过横竖切来转移,用记忆化搜索很容易实现

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

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 #define INF (1<<29)
 7 int d[16][8][8][8][8];
 8 int a[8][8];
 9 int calc(int x1,int y1,int x2,int y2){
10     int res=0;
11     for(int i=x1; i<=x2; ++i){
12         for(int j=y1; j<=y2; ++j) res+=a[i][j];
13     }
14     return res;
15 }
16 int dp(int k,int x1,int y1,int x2,int y2){
17     if(d[k][x1][y1][x2][y2]!=-1) return d[k][x1][y1][x2][y2];
18     if(k==0) return d[k][x1][y1][x2][y2]=calc(x1,y1,x2,y2)*calc(x1,y1,x2,y2);
19     int res=INF;
20     for(int i=x1; i<x2; ++i){
21         res=min(res,dp(k-1,x1,y1,i,y2)+calc(i+1,y1,x2,y2)*calc(i+1,y1,x2,y2));
22         res=min(res,dp(k-1,i+1,y1,x2,y2)+calc(x1,y1,i,y2)*calc(x1,y1,i,y2));
23     }
24     for(int i=y1; i<y2; ++i){
25         res=min(res,dp(k-1,x1,y1,x2,i)+calc(x1,i+1,x2,y2)*calc(x1,i+1,x2,y2));
26         res=min(res,dp(k-1,x1,i+1,x2,y2)+calc(x1,y1,x2,i)*calc(x1,y1,x2,i));
27     }
28     return d[k][x1][y1][x2][y2]=res;
29 }
30 int main(){
31     memset(d,-1,sizeof(d));
32     int n;
33     scanf("%d",&n);
34     int sum=0;
35     for(int i=0; i<8; ++i){
36         for(int j=0; j<8; ++j) scanf("%d",&a[i][j]),sum+=a[i][j];
37     }
38     double avg=sum*1.0/n;
39     double ans = sqrt(dp(n-1,0,0,7,7)*1.0/n-avg*avg);
40     printf("%.3f\n",ans);
41     return 0;
42 }

 

posted @ 2016-03-11 17:22  WABoss  阅读(239)  评论(0编辑  收藏  举报