您的位置:首页 > 其它

poj1191 [NOI1999] 棋盘分割(dp)

2017-07-30 11:53 537 查看
黑书1.5.1例题2.矩阵越分越小,显然是可以递归处理的。所以我们就想到了dp。求σ=∑i=1n(xi−x¯)2n−−−−−−−−√ 可以化简为 σ2=1n∑i=1nx2i−(x¯)2.平均数是不变的,所以我们只需dp求分成n个矩阵和的平方的和最小值。dp[k][x1][y1][x2][y2]表示把矩阵(x1,y1,x2,y2)(左上角坐标x1,y1,右下角坐标x2,y2)切k刀,能获得的最小值。dp[0]见注释。转移方程为dp[k][x1][y1][x2][y2] = min{

dp[0][x1][y1][t][y2]+dp[k-1][t+1][y1][x2][y2], (x1 <= t < x2)

dp[k-1][x1][y1][t][y2]+dp[0][t+1][y1][x2][y2], (x1 <= t < x2)

dp[0][x1][y1][x2][t]+dp[k-1][x1][t+1][x2][y2], (y1 <= t < y2)

dp[k-1][x1][y1][x2][t]+dp[0][x1][t+1][x2][y2],(y1 <= t < y2)

} 设棋盘边长为m,那么状态数目为m4n,决策数目为O(m),预处理sum数组为O(m2),状态转移时间是O(1)的,所以总的时间复杂度是O(m5n),而m=8,n<16.足够了。

#include <cstdio>
#include <cmath>
#include <cstring>
#define inf 0x7fffffff
int map[9][9],n,sum[9][9],tot=0;
double dp[16][9][9][9][9];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
template <typename T>
inline T min(T x,T y){return x<y?x:y;}
inline double calc(int x1,int y1,int x2,int y2){
double ans=sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
return ans*ans;
}
int main(){
//  freopen("a.in","r",stdin);
n=read();
for(int i=1;i<=8;++i)
for(int j=1;j<=8;++j)
map[i][j]=read();
for(int i=1;i<=8;++i)
for(int j=1;j<=8;++j){
//sum[i][j]---sum of matrix(1,1,i,j)
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+map[i][j];
tot+=map[i][j];
}
for(int x1=1;x1<=8;++x1)
for(int y1=1;y1<=8;++y1)
for(int x2=x1;x2<=8;++x2)
for(int y2=y1;y2<=8;++y2)
dp[0][x1][y1][x2][y2]=calc(x1,y1,x2,y2);//dp[0]--marix(x1,y1,x2,y2)的和的平方
for(int k=1;k<n;++k)//切成n块,n-1刀。
for(int x1=1;x1<=8;++x1)
for(int y1=1;y1<=8;++y1)
for(int x2=x1;x2<=8;++x2)
for(int y2=y1;y2<=8;++y2){
dp[k][x1][y1][x2][y2]=inf;
for(int t=x1;t<x2;++t){//竖着切。
dp[k][x1][y1][x2][y2]=min(dp[k][x1][y1][x2][y2],dp[k-1][x1][y1][t][y2]+dp[0][t+1][y1][x2][y2]);
dp[k][x1][y1][x2][y2]=min(dp[k][x1][y1][x2][y2],dp[0][x1][y1][t][y2]+dp[k-1][t+1][y1][x2][y2]);
}
for(int t=y1;t<y2;++t){//横着切
dp[k][x1][y1][x2][y2]=min(dp[k][x1][y1][x2][y2],dp[k-1][x1][y1][x2][t]+dp[0][x1][t+1][x2][y2]);
dp[k][x1][y1][x2][y2]=min(dp[k][x1][y1][x2][y2],dp[0][x1][y1][x2][t]+dp[k-1][x1][t+1][x2][y2]);
}
}
double ans=dp[n-1][1][1][8][8]/n-(tot*1.0/n)*(tot*1.0/n);
printf("%.3f\n",sqrt(ans));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: