POJ 1191 棋盘分割(记忆化搜)

126 篇文章 2 订阅
46 篇文章 0 订阅

黑书上的dp原题。P116。很经典的一道题目,注意转化啊。

中文题,题意很简单。^_^,黑书上的原题,前几天刚做过。

先把

化简的 σ2 = 1/n*∑xi2 - ¯x;

也就是说求出∑xi2的最小值就可以了。

dp(x1, y1, x2, y2, k),表示(x1, y1), (x2, y2)所确定的区间上切k刀分成k+1块的最优值。

dp(x1, y1, x2, y2, k) = min(dp(x1, y1, i - 1, y2, k - 1) + sum(i, y1, x2, y2), dp(i, y1, x2, y2, k - 1) + sum(x1, y1, i - 1, y2),

            dp(x1, y1, x2, j - 1, k - 1) + sum(x1, j, x2, y2), dp(x1, j, x2, y2, k - 1) + sum(x1, y1, x2, j - 1));

(x1 < i <= x2; y1 < j <= y2;)

然后记忆化搜索

PS:刚哥写的,我就不在赘述了啊。

棋盘分割
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 11950 Accepted: 4210

Description

将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行) 

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。 
均方差 ,其中平均值 ,x i为第i块矩形棋盘的总分。 
请编程对给出的棋盘及n,求出O'的最小值。 

Input

第1行为一个整数n(1 < n < 15)。 
第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。 

Output

仅一个数,为O'(四舍五入精确到小数点后三位)。

Sample Input

3
1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 3

Sample Output

1.633
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-7
#define M 1000100
///#define LL __int64
#define LL long long
#define INF 0x3fffffff
#define PI 3.1415926535898

using namespace std;

const int maxn = 20;

int dp[maxn][maxn][maxn][maxn][maxn];
int mp[maxn][maxn];
int sum[maxn][maxn];
int s[maxn][maxn][maxn][maxn];

int n;

int dfs(int x1, int y1, int x2, int y2, int k)
{
    if(dp[x1][y1][x2][y2][k] != -1)
        return dp[x1][y1][x2][y2][k];
    if(k == 1)
    {
        dp[x1][y1][x2][y2][k] = s[x1][y1][x2][y2];
        return dp[x1][y1][x2][y2][k];
    }
    int Min = INF;
    for(int a = x1; a < x2; a++)
    {
        Min = min(dfs(x1,y1,a,y2,k-1)+s[a+1][y1][x2][y2], Min);
        Min = min(dfs(a+1,y1,x2,y2,k-1)+s[x1][y1][a][y2], Min);
    }
    for(int b = y1; b < y2; b++)
    {
        Min = min(dfs(x1,y1,x2,b,k-1)+s[x1][b+1][x2][y2], Min);
        Min = min(dfs(x1,b+1,x2,y2,k-1)+s[x1][y1][x2][b], Min);
    }
    dp[x1][y1][x2][y2][k] = Min;
    return dp[x1][y1][x2][y2][k];
}

int main()
{
    while(cin >>n)
    {
        int cnt = 0;
        for(int i = 1; i <= 8; i++)
        {
            for(int j = 1; j <= 8; j++)
            {
                cin >>mp[i][j];
                cnt += mp[i][j];
            }
        }
        memset(sum, 0, sizeof(sum));
        for(int i = 1; i <= 8; i++)
        {
            for(int j = 1; j <= 8; j++)
                sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+mp[i][j];
        }
        for(int i = 1; i <= 8; i++)
            for(int j = 1; j <= 8; j++)
                for(int x = 1; x <= 8; x++)
                    for(int y = 1; y <= 8; y++)
                        for(int k = 1; k <= n; k++)
                            dp[i][j][x][y][k] = -1;

        for(int i = 1; i <= 8; i++)
        {
            for(int j = 1; j <= 8; j++)
            {
                for(int x = 1; x <= 8; x++)
                {
                    for(int y = 1; y <= 8; y++)
                    {
                        s[i][j][x][y] = sum[x][y]+sum[i-1][j-1]-sum[i-1][y]-sum[x][j-1];
                        s[i][j][x][y] *= s[i][j][x][y];
                    }
                }
            }
        }
        printf("%.3lf\n", sqrt((dfs(1,1,8,8,n)*1.0/n)-((cnt*1.0/n)*(cnt*1.0/n))));
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值