棋盘分割 POJ - 1191(暴力枚举型dp)

思路

先预处理出前缀和,然后dp[k][x1][y1][x2][y2]表示,切k次,左上角为x1,y1,右下角为x2,y2的矩阵的最小均方差。
然后暴力枚举就行。
棋盘分割 POJ - 1191(暴力枚举型dp)_第1张图片

代码

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn=1e2+8;
typedef long long ll;
int mp[10][10];
int sum[10][10];
int dp[16][10][10][10][10];
int n;
int dfs(int k,int x1,int y1,int x2,int y2)
{
    int mid,ans=1e8+2;
    for(mid=x1+1;mid//横着切
        ans=min(ans,dp[k-1][x1][y1][mid][y2]+dp[1][mid][y1][x2][y2]);
        ans=min(ans,dp[k-1][mid][y1][x2][y2]+dp[1][x1][y1][mid][y2]);
    }
    for(mid=y1+1;mid//竖着切
        ans=min(ans,dp[k-1][x1][y1][x2][mid]+dp[1][x1][mid][x2][y2]);
        ans=min(ans,dp[k-1][x1][mid][x2][y2]+dp[1][x1][y1][x2][mid]);
    }   
    return ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    while(scanf("%d",&n)!=EOF)
    {
        double s=0.f;
        int k,x1,x2,y1,y2;
        memset(mp,0,sizeof(mp));
        memset(sum,0,sizeof(sum));
        int i,j;
       for(i=1;i<=8;i++){
        for(j=1;j<=8;j++){
            scanf("%d",&mp[i][j]);
            mp[i][j]+=mp[i-1][j]+mp[i][j-1]-mp[i-1][j-1];
        }
    }
        for(x1=0;x1<8;x1++){
        for(y1=0;y1<8;y1++){
            for(x2=x1+1;x2<=8;x2++){
                for(y2=y1+1;y2<=8;y2++){
                    int temp=mp[x2][y2]-mp[x1][y2]-mp[x2][y1]+mp[x1][y1];
                    dp[1][x1][y1][x2][y2]=temp*temp;
                }
            }
        }
    }
    for(k=2;k<=n;k++){
        for(x1=0;x1<8;x1++){
            for(y1=0;y1<8;y1++){
                for(x2=x1+1;x2<=8;x2++){
                    for(y2=y1+1;y2<=8;y2++){
                        dp[k][x1][y1][x2][y2]=dfs(k,x1,y1,x2,y2);
                    }
                }
            }
        }
    }
    double ans = 1.0*dp[n][0][0][8][8]/n - 1.0*mp[8][8]*mp[8][8]/(n*n);
    printf("%.3f\n",sqrt(ans));
    }
    return 0;
}

你可能感兴趣的:(动态规划)