UVA 1629 Cake slicing

来源:互联网 发布:win8安装软件乱码 编辑:程序博客网 时间:2024/05/17 21:46

题目链接:http://acm.hust.edu.cn/vjudge/problem/51190


题意:有n*m规模的蛋糕,有一些格子上有樱桃,现在对于一个矩形的蛋糕,我们只能选择一个位置横着切到底,或竖着切到底。问怎样切使得每一块蛋糕上有一颗樱桃,而且切割总长度最小。


思路:记忆化搜索,dp[x][y][Lx][Ly]表示切割左上角为(x,y)且x方向长度为Lx,y方向长度为Ly范围内蛋糕的最小总长度。递归到范围内只有一颗樱桃时停止,否则就先枚举横着切的位置计算一遍,再枚举竖着切的位置计算一遍取最小值。注意这里枚举切割位置会将蛋糕分为两部分,计算之前还要判断一下能否这样切,即分为两部分的蛋糕每部分都至少含有一颗樱桃。可以预处理出来每一行的前缀和。那么对于n*m的格子就可以通过O(n)的复杂度计算范围内樱桃的个数。


#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <cstdlib>#include <iostream>#include <algorithm>#include <stack>#include <map>#include <set>#include <vector>#include <sstream>#include <queue>#include <utility>using namespace std;#define rep(i,j,k) for (int i=j;i<=k;i++)#define Rrep(i,j,k) for (int i=j;i>=k;i--)#define Clean(x,y) memset(x,y,sizeof(x))#define LL long long#define ULL unsigned long long#define inf 0x7fffffff#define mod 100000007const int maxn = 22;int num[maxn][maxn];int sum[maxn][maxn];LL dp[maxn][maxn][maxn][maxn];int n,m,k;void init(){    Clean(num,0);    Clean(sum,0);    int tx,ty;    rep(i,1,k)    {        scanf("%d%d",&tx,&ty);        num[tx][ty] = 1;    }    rep(i,1,n)    {        rep(j,1,m) sum[i][j] = sum[i][j-1] + num[i][j];    }    Clean(dp,-1);}int count( int x , int y , int Lx , int Ly ) //计算范围内樱桃个数{    int ans = 0;    rep(i,x,x+Lx-1)        ans += sum[i][y+Ly-1] - sum[i][y-1];    return ans;}LL dfs( int x , int y , int Lx , int Ly ){    if ( dp[x][y][Lx][Ly] != -1 ) return dp[x][y][Lx][Ly];    if ( count( x , y , Lx , Ly ) == 1 ) return dp[x][y][Lx][Ly] = 0;    LL ans = inf;    rep(i,1,Lx-1) //横着切        if ( count( x , y , i , Ly ) >= 1 && count( x + i  , y , Lx - i , Ly ) >= 1 )            ans = min( ans , dfs( x , y , i , Ly ) + dfs( x + i   , y , Lx - i , Ly ) + Ly );    rep(i,1,Ly-1) //竖着切        if ( count( x , y , Lx , i ) >= 1 && count( x  , y + i , Lx , Ly - i ) >= 1 )            ans = min( ans , dfs( x , y , Lx , i ) + dfs( x  , y + i , Lx , Ly - i ) + Lx );    return dp[x][y][Lx][Ly] = ans;}int main(){    int kase = 0;    while( cin>>n>>m>>k )    {        init();        printf( "Case %d: %lld\n" , ++kase ,  dfs( 1 , 1 , n , m ) );    }    return 0;}


0 0
原创粉丝点击