POJ1191 棋盘分割 ACM解题报告(DFS+DP)

最近期末复习,不能多刷题,只能每天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;
}

你可能感兴趣的:(ACM,poj)