最近期末复习,不能多刷题,只能每天A一个吧,今天还是深搜,这题比前两次的简单,不需要简直,只要DP即可,首先看这题目挺吓人的,我一开始也是二用了8个形参,结果DP根本无法记录,后来发现里面的3个居然是重复的,写完后就是不能过sample,对着百度的代码仔细检查,发现了居然每种情况更新最小值写在了循环外,也是基本功渣啊。
本题其实不难,就是记录切割后的矩形的坐标即可,然后开始棋盘上每块矩形的和必须打表计算,还有就是化简表达式,化简均方差的表达式得根号下sigma(xi)^2/n-ave^2,就会简单很多。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; int a[10][10],sum[10][10],dp[16][10][10][10][10],n; int summ(int x1,int x2,int y1,int y2) { return sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];//计算每块切割后舍弃的矩形的和,画图看会比较清晰 } int dfs(int dao,int row1,int row2,int col1,int col2) { int temp,s1,s2,m=100000000; if(dp[dao][row1][row2][col1][col2]!=-1) return dp[dao][row1][row2][col1][col2];//DP记录 if(dao==n-1)//n块就是n-1刀 { s1=summ(row1,row2,col1,col2); return dp[dao][row1][row2][col1][col2]=s1*s1; } for(int i=row1;i<row2;i++) { s1=summ(i+1,row2,col1,col2); s2=summ(row1,i,col1,col2); temp=min(s1*s1+dfs(dao+1,row1,i,col1,col2),s2*s2+dfs(dao+1,i+1,row2,col1,col2)); if(m>temp) m=temp;//犯二的地方,居然把这个写在了循环外我也是醉了。。。 } for(int i=col1;i<col2;i++) { s1=summ(row1,row2,col1,i); s2=summ(row1,row2,i+1,col2); temp=min(s1*s1+dfs(dao+1,row1,row2,i+1,col2),s2*s2+dfs(dao+1,row1,row2,col1,i)); if(m>temp) m=temp; } return dp[dao][row1][row2][col1][col2]=m; } int main() { int rev; memset(sum,0,sizeof(sum)); memset(a,0,sizeof(a)); memset(dp,-1,sizeof(dp)); cin>>n; for(int i=1; i<=8; i++) { for(int j=1; j<=8; j++) { scanf("%d",&a[i][j]); sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];//先计算每块顶点为(1,1)的矩形的和 } } rev=dfs(0,1,8,1,8); //printf("%d ",rev); double o; o=sqrt(rev*1.0/n-sum[8][8]*sum[8][8]*1.0/(n*n)); printf("%.3lf\n",o); return 0; }