bzoj3810: [Coci2015]Stanovi(记忆化搜索)

  实际上切出来的矩阵在原矩阵上的位置是不重要的。。。重要的只有矩阵的大小和上下左右是否在边界上。

  于是我们可以设f[x][y][l][r][u][d]表示x*y的矩阵上下左右是不是边界的最小代价。

  记忆化搜索一下横着切和竖着切。

  但是这样会被卡。。我们令x>=y l>=r u>=d可以减少很多相同的状态数,而且答案是不变的,这样常数小很多才能过

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio> 
#include<algorithm>
#define ll long long 
using namespace std;
const int maxn=310;
int n,m,k;
ll f[maxn][maxn][2][2][2][2];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
    while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar();
    k*=f;
}
ll dfs(int x,int y,int l,int r,int u,int d)
{
    if(x<y)swap(x,y),swap(l,d),swap(u,r);
    if(u<d)swap(u,d);if(l<r)swap(l,r);
    if(f[x][y][l][r][u][d]!=-1)return f[x][y][l][r][u][d];
    ll ans=1ll*(x*y-k)*(x*y-k);
    if(l||r||(u&&d))for(int i=1;i<x;i++)ans=min(ans,dfs(i,y,l,r,u,0)+dfs(x-i,y,l,r,0,d));
    if(u||d||(l&&r))for(int i=1;i<y;i++)ans=min(ans,dfs(x,i,l,0,u,d)+dfs(x,y-i,0,r,u,d));
//    printf("%d %d %d %d %d %d %d
",x,y,l,r,u,d,ans);
    return f[x][y][l][r][u][d]=ans;
}
int main()
{
    read(n);read(m);read(k);
    memset(f,-1,sizeof(f));
    printf("%lld
",dfs(n,m,1,1,1,1));
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Sakits/p/7626988.html