http://poj.org/problem?id=1191
明白几点:
1)最终的均方差可以转变成:sqrt( sigma[ i:1-m ]( xi*xi ) / n - ( sum(all) / n )*( sum(all) / n ) ),不懂这个转换的需要补一下数学基础;所以最终决定最小值的是sigma[ i:1-m ]( xi*xi )。
2)动归含义:
dp[n][x1][x2][y1][y2]表示由x1,x2,y1,y2组成的矩形要生成n块小矩阵,均方差的最小值(sigma[ i:1-m ]( xi*xi ));它的值需要遍历所有横向切、纵向切的可能,然后取最小值。最终结果是dp[n][1][8][1][8],不多说。
# include<iostream> # include<string.h> # include<cmath> using namespace std; # define N 16 # define INF 1000000000 int data[9][9]; int dp[N][9][9][9][9]; int onePart[9][9][9][9]; int OnePart(int x1, int x2, int y1, int y2) { int sum=0; for(int x=x1;x<=x2;x++) { for(int y=y1;y<=y2;y++) { sum+=data[x][y]; } } return sum; } int Partition(int n, int x1, int x2, int y1, int y2) { if(dp[n][x1][x2][y1][y2]!=-1) { return dp[n][x1][x2][y1][y2]; } else { int x,y,t,t1,t2; dp[n][x1][x2][y1][y2]=INF; //up-down for(x=x1;x<x2;x++) //x<x2, not x<=x2 { //continue partition up t1=onePart[x+1][x2][y1][y2]+Partition(n-1,x1,x,y1,y2); //onePart[x+1][x2][y1][y2], not onePart[x][x2][y1][y2] //continue partition down t2=onePart[x1][x][y1][y2]+Partition(n-1,x+1,x2,y1,y2); t = t1<t2? t1:t2 ; dp[n][x1][x2][y1][y2] = dp[n][x1][x2][y1][y2]<t? dp[n][x1][x2][y1][y2]:t ; } //left-right for(y=y1;y<y2;y++) { //continue partition left t1=onePart[x1][x2][y+1][y2]+Partition(n-1,x1,x2,y1,y); //continue partition right t2=onePart[x1][x2][y1][y]+Partition(n-1,x1,x2,y+1,y2); t = t1<t2? t1:t2 ; dp[n][x1][x2][y1][y2] = dp[n][x1][x2][y1][y2]<t? dp[n][x1][x2][y1][y2]:t ; } return dp[n][x1][x2][y1][y2]; } } int main() { int x1,x2,y1,y2,x,y,n,t; int sum=0; cin>>n; for(x=1;x<=8;x++) { for(y=1;y<=8;y++) { cin>>data[x][y]; sum+=data[x][y]; } } memset(dp,-1,sizeof(dp)); for(x1=1;x1<=8;x1++) { for(x2=x1;x2<=8;x2++) { for(y1=1;y1<=8;y1++) { for(y2=y1;y2<=8;y2++) { t=OnePart(x1,x2,y1,y2); onePart[x1][x2][y1][y2]=t*t; dp[1][x1][x2][y1][y2]=t*t; } } } } Partition(n,1,8,1,8); printf("%.3f\n", sqrt( dp[n][1][8][1][8]*1.0/n - (sum*1.0/n)*(sum*1.0/n) ) ); return 0; }