首页 > 代码库 > poj 1191 棋盘切割 (压缩dp+记忆化搜索)

poj 1191 棋盘切割 (压缩dp+记忆化搜索)

一,题意:

中文题

二。分析:

主要利用压缩dp与记忆化搜索思想

三,代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
const int Big=20000000;
int Mat[10][10];
int N;
int sum[10][10];
int dp[20][10][10][10][10];
void unit()
{//求和用sum[i][j]表示ij到左上角的和
    int total;
    for(int i=1; i<=8; i++)
        for(int j=1; j<=8; j++)
        {
            total=Mat[i][j];
            int x_1,y_1;
            x_1=i-1;
            y_1=j-1;
            if(x_1>0)
                total+=sum[x_1][j];
            if(y_1>0)
                total+=sum[i][y_1];
            if(x_1>0&&y_1>0)
                total-=sum[x_1][y_1];
            sum[i][j]=total;
        }
}

int account(int x_1,int y_1,int x_2,int y_2)
{//求(x_1,y_1)到(x_2。y_2)区间和
    int total=sum[x_2][y_2];
    int x_3,y_3;
    x_3=x_1-1;
    y_3=y_1-1;
    if(x_3>0)
        total-=sum[x_3][y_2];
    if(y_3>0)
        total-=sum[x_2][y_3];
    if(x_3>0&&y_3>0)
        total+=sum[x_3][y_3];
    return total*total;
}

int solve(int k,int x_1,int y_1,int x_2,int y_2)
{//记忆化dp
    if(dp[k][x_1][y_1][x_2][y_2]!=-1)
        return dp[k][x_1][y_1][x_2][y_2];
    if(k==1)
        return dp[k][x_1][y_1][x_2][y_2]=account(x_1,y_1,x_2,y_2);
    if(k>1)
    {
        int Min=Big;
        for(int i=y_1;i<y_2;i++)
        {//横向分割
            int first=account(x_1,y_1,x_2,i);
            int second=account(x_1,i+1,x_2,y_2);
            first+=solve(k-1,x_1,i+1,x_2,y_2);
            second+=solve(k-1,x_1,y_1,x_2,i);
            if(first>second)
                first=second;
            if(Min>first)
                Min=first;
        }
        for(int j=x_1;j<x_2;j++)
        {//纵向分割
            int first=account(x_1,y_1,j,y_2);
            int second=account(j+1,y_1,x_2,y_2);
            first+=solve(k-1,j+1,y_1,x_2,y_2);
            second+=solve(k-1,x_1,y_1,j,y_2);
            if(first>second)
                first=second;
            if(Min>first)
                Min=first;
        }
        return dp[k][x_1][y_1][x_2][y_2]=Min;
    }
    return dp[k][x_1][y_1][x_2][y_2]=Big;
}

int main()
{
    while(scanf("%d",&N)!=EOF)
    {
        double total=0.0;
        for(int i=1; i<=8; i++)
            for(int j=1; j<=8; j++)
            {
                 scanf("%d",&Mat[i][j]);
                 total+=Mat[i][j];
            }
        unit();
        memset(dp,-1,sizeof(dp));
         total=(total/N)*(total/N);
        double key=solve(N,1,1,8,8);
        key=key/N;
       key=sqrt(key-total);
       printf("%0.3f\n",key);
    }
    return 0;
}


poj 1191 棋盘切割 (压缩dp+记忆化搜索)