BZOJ1560:[JSOI2009]火星藏宝图 dp
BZOJ3743:[Coci2015]Kamp 树形dp

BZOJ3810:[Coci2015]Stanovi dp

shinbokuow posted @ Mar 06, 2015 11:08:32 AM in BZOJ with tags dp , 2313 阅读

思路:

首先有一个性质:当前的矩形必定可以被划分成两个子矩形.

无脑dp.

记录四个状态表示当前矩形的四条边是不是原来的大矩形的边.

然后记忆化搜索即可.

(要非常注意常数优化)

#include<cstdio>
#include<cstring>
#include<cctype>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
 
#define INF 1ll<<60
 
#define N 310
long long f[2][2][2][2][N][N];
int n,m,k;
 
inline long long calc(int w,int h,int a,int b,int c,int d){
    if(w>h){
        swap(w,h);
        int aa=c,bb=d,cc=b,dd=a;
        a=aa,b=bb,c=cc,d=dd;
        if(a>b)swap(a,b);
        if(c>d)swap(c,d);
    }
    if(f[a][b][c][d][w][h]!=-1)return f[a][b][c][d][w][h];
    if(!a&&!b&&!c&&!d)return f[a][b][c][d][w][h]=INF;
    long long re=(long long)(w*h-k)*(w*h-k);
    if(a+b+c>0&&a+b+d>0)
        for(int i=1;i<w;++i)re=min(re,calc(i,h,a,b,c,0)+calc(w-i,h,a,b,0,d));
    if(a+c+d>0&&b+c+d>0)
        for(int i=1;i<h;++i)re=min(re,calc(w,i,a,0,c,d)+calc(w,h-i,0,b,c,d));
    return f[a][b][c][d][w][h]=re;
}
 
int main(){
    scanf("%d%d%d",&n,&m,&k);
    register int i,j;
     
    memset(f,-1,sizeof f);
    printf("%lld",calc(n,m,1,1,1,1));
     
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter