习题9-3 切蛋糕 UVa1629
2015-10-08 15:09
453 查看
1.题目描述:点击打开链接
2.解题思路:本题属于棋盘型dp问题。根据题意,我们需要完整的描述一个矩形,以便于进行状态的转移,可以用(r,c,w,h)来描述一个矩形,(r,c)是矩形的左上角坐标。w是矩形的宽,h是矩形的高。那么不难得到如下的两个状态转移方程:
(横切)
dp(r,c,w,h)=max{dp(r,c,w,h),w+dp(r,c,w,i)+dp(r+i,c,w,h-i)}(1<=i<=h);
(竖切)
dp(r,c,w,h)=max{dp(r,c,w,h),h+dp(r,c,i,h)+dp(r,c+i,w-i,h)}(1<=i<=w);
上述方程描述的是横切和竖切两种情况,可以利用记忆化搜索计算。不过根据题意,需要保证切出来的两个矩形都含有一个樱桃。可以事先递推计算从(r,c)到右下角这个矩形的总的樱桃个数。不妨用val数组表示,则有:
val(r,c)=val(r,c)+val(r+1,c)+val(r,c+1)-val(r+1,c+1)+g[r][c];
那么计算矩形(r,c)~(r+h,c+w)内部的樱桃个数就是:val(r,c)-val(r+h,c)-val(r,c+w)+val(r+h,c+w)。
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<list>
#include<complex>
#include<functional>
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
typedef long long ll;
typedef pair <int,int> P;
const int N=20+5;
const int INF=1e9;
int g
;
int d
;
int vis
;
int n,m,k;
int ok(int x,int y,int w,int h)
{
return vis[x][y]-vis[x+h][y]-vis[x][y+w]+vis[x+h][y+w];
}
int dp(int x,int y,int w,int h)
{
int&ans=d[x][y][w][h];
if(ans!=-1)return ans;
if(ok(x,y,w,h)==1)return ans=0;
if(!ok(x,y,w,h))return ans=INF;
int tmp=INF;
for(int i=1;i<h;i++)
if(ok(x,y,w,i)&&ok(x+i,y,w,h-i))
tmp=min(tmp,w+dp(x,y,w,i)+dp(x+i,y,w,h-i));
for(int i=1;i<w;i++)
if(ok(x,y,i,h)&&ok(x,y+i,w-i,h))
tmp=min(tmp,h+dp(x,y,i,h)+dp(x,y+i,w-i,h));
return ans=tmp;
}
int main()
{
int kase=0;
while(~scanf("%d%d%d",&n,&m,&k))
{
me(g);me(vis);
int x,y;
for(int i=0;i<k;i++)
{
scanf("%d%d",&x,&y);
x--,y--;
g[x][y]=1;
}
for(int i=n-1;i>=0;i--)
for(int j=m-1;j>=0;j--)
vis[i][j]+=vis[i+1][j]+vis[i][j+1]-vis[i+1][j+1]+g[i][j];
memset(d,-1,sizeof(d));
int ans=dp(0,0,m,n);
printf("Case %d: %d\n",++kase,ans);
}
}
2.解题思路:本题属于棋盘型dp问题。根据题意,我们需要完整的描述一个矩形,以便于进行状态的转移,可以用(r,c,w,h)来描述一个矩形,(r,c)是矩形的左上角坐标。w是矩形的宽,h是矩形的高。那么不难得到如下的两个状态转移方程:
(横切)
dp(r,c,w,h)=max{dp(r,c,w,h),w+dp(r,c,w,i)+dp(r+i,c,w,h-i)}(1<=i<=h);
(竖切)
dp(r,c,w,h)=max{dp(r,c,w,h),h+dp(r,c,i,h)+dp(r,c+i,w-i,h)}(1<=i<=w);
上述方程描述的是横切和竖切两种情况,可以利用记忆化搜索计算。不过根据题意,需要保证切出来的两个矩形都含有一个樱桃。可以事先递推计算从(r,c)到右下角这个矩形的总的樱桃个数。不妨用val数组表示,则有:
val(r,c)=val(r,c)+val(r+1,c)+val(r,c+1)-val(r+1,c+1)+g[r][c];
那么计算矩形(r,c)~(r+h,c+w)内部的樱桃个数就是:val(r,c)-val(r+h,c)-val(r,c+w)+val(r+h,c+w)。
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<list>
#include<complex>
#include<functional>
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
typedef long long ll;
typedef pair <int,int> P;
const int N=20+5;
const int INF=1e9;
int g
;
int d
;
int vis
;
int n,m,k;
int ok(int x,int y,int w,int h)
{
return vis[x][y]-vis[x+h][y]-vis[x][y+w]+vis[x+h][y+w];
}
int dp(int x,int y,int w,int h)
{
int&ans=d[x][y][w][h];
if(ans!=-1)return ans;
if(ok(x,y,w,h)==1)return ans=0;
if(!ok(x,y,w,h))return ans=INF;
int tmp=INF;
for(int i=1;i<h;i++)
if(ok(x,y,w,i)&&ok(x+i,y,w,h-i))
tmp=min(tmp,w+dp(x,y,w,i)+dp(x+i,y,w,h-i));
for(int i=1;i<w;i++)
if(ok(x,y,i,h)&&ok(x,y+i,w-i,h))
tmp=min(tmp,h+dp(x,y,i,h)+dp(x,y+i,w-i,h));
return ans=tmp;
}
int main()
{
int kase=0;
while(~scanf("%d%d%d",&n,&m,&k))
{
me(g);me(vis);
int x,y;
for(int i=0;i<k;i++)
{
scanf("%d%d",&x,&y);
x--,y--;
g[x][y]=1;
}
for(int i=n-1;i>=0;i--)
for(int j=m-1;j>=0;j--)
vis[i][j]+=vis[i+1][j]+vis[i][j+1]-vis[i+1][j+1]+g[i][j];
memset(d,-1,sizeof(d));
int ans=dp(0,0,m,n);
printf("Case %d: %d\n",++kase,ans);
}
}
相关文章推荐
- linux中patch的用法
- Maven
- c++泛型
- 面向对象之封装性理解
- 使用Java编写图形化的菜单的教程
- 【学习笔记javascript设计模式与开发实践(闭包和高阶函数)----3】
- str.replace替换的用法
- stm8 读取电表芯片 att7053 io口模拟 spi
- opencv第一次成功人脸检测(初级)
- Jenkins CI持续集成(基于Git)
- hdu 1061 Rightmost Digit
- 算法导论12.4随机构建二叉搜索树 练习总结
- arc和mrc混用
- ios开发——日常之在Xcode6 后如何创建类目和延展(category&extension&protocol)
- .net在linux下部署项目
- qt入门小程序
- 数据输入控件使用简介
- iOS开发--点击屏幕获得屏幕坐标
- Sichuan Province 2012 F Fold The Paper
- stm8 io口 spi模拟,可用于RC522