poj1191 棋盘分割 (DP)

来源:互联网 发布:电算化会计软件下载 编辑:程序博客网 时间:2024/04/29 23:43

题目链接:http://poj.org/problem?id=1191


//题目意思:在一个8*8的棋盘中要划分成n块,并且方差最小
//解题思路:用一个5维的数组来记录状态st[k][x1][y1][x2][y2],表示在第k次时从(x1,y1)到(x2,y2)的矩形切出的和的平方的和(就是已经分两块了,只是这个数组没表示从哪里切)。然后递归到前面一次,选择两个中的一块继续递归。

//0ms AC,代码如下:#include<iostream>#include<cstdio>#include<math.h>using namespace std;#define min(a,b) ((a)<(b)) ? (a) : (b)const int M =8;int n;int num[M+1][M+1]={0};//记录各个格子的值int sum[M+1][M+1]={0};//记录(0,0)到(x,y)矩形的和int st[15][M+1][M+1][M+1][M+1]; int sumFun(int x1,int y1,int x2,int y2)//返回矩形和的平方{int temp;temp=sum[x2][y2]+sum[x1-1][y1-1]-sum[x1-1][y2]-sum[x2][y1-1];return temp*temp;}int dp(int k,int x1,int y1,int x2,int y2){int i,j,temp=1000000000;if(st[k][x1][y1][x2][y2]!=-1)//已计算过了不用再算return st[k][x1][y1][x2][y2];else if(k==1||x1==x2||y1==y2){return st[k][x1][y1][x2][y2]=sumFun(x1,y1,x2,y2);}else {for(i=x1;i<x2;i++){temp=min(temp,min(sumFun(i+1, y1, x2, y2)+dp(k-1, x1, y1, i, y2),sumFun(x1, y1, i, y2)+dp(k-1, i+1, y1, x2, y2)));}for(j=y1;j<y2;j++){temp=min(temp, min(dp(k-1, x1, y1, x2, j)+sumFun(x1, j+1, x2, y2), dp(k-1, x1, j+1, x2, y2)+sumFun(x1, y1, x2, j)));}st[k][x1][y1][x2][y2]=temp;}return temp;}void init(){scanf("%d",&n);int i,j;for(i=0;i<M+1;i++)for(j=0;j<M+1;j++){if(i==0||j==0){num[i][j]=0;sum[i][j]=0;}else {scanf("%d",&num[i][j]);sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+num[i][j];}}}void makeSt()//st的初始化{int i,j,x,y,k;for(k=0;k<15;k++)for(i=0;i<=M;i++)for(j=0;j<=M;j++)for(x=0;x<=M;x++)for(y=0;y<=M;y++)st[k][i][j][x][y]=-1;}int main(){init();makeSt();double res=(double)sqrt((double)dp(n,1,1,M,M)/(double)n-(double)pow((double)sqrt((double)sumFun(1,1,M,M))/(double)n,2.0));//之前因为没有强制转换为double,wa了好多次==!printf("%.3lf\n",res);return 0;}

原创粉丝点击