LRJ入门经典-0903切蛋糕305

试题描述

如图所示有一个矩形蛋糕,上面划分成了n行m列的网格,一些网格内放着樱桃。现在要根据如下规则切蛋糕:

1.切开的每一块必须是矩形(包括正方形)

2.切蛋糕时必须沿着网格线,不能拐弯

3.切开的每一块蛋糕上有且仅有一个樱桃

下图是一种切割方法:

这种方法需要切割的边数为2+4=6

以下是另一种切割方法:

这种方法需要切割的边数为3+2=5

现在给定蛋糕的形状和上面樱桃的分布,要求求出切割边数最少的方案。

输入
第一行包含三个正整数n,m和k(1<=n,m<=20),k表示樱桃数量
以下k行每行包含两个正整数,表示每个樱桃所在的行和列
输出
输出最优方案的切割边数
输入示例
3 4 3
1 2
2 3
3 2
输出示例
5

  思路:明显一个递归,相信各位大佬忧虑的是如何在dfs中储存这个区域,我推荐一个方法,可以int dfs(int x,int y,int w,int h)其中x,y表示左上的点的坐标,而w,h表示这个矩形的    长和宽,再加个记忆化,dp[30][30][30][30];就可以再优化。

  详解见代码注释:

  

#include<bits/stdc++.h>//万能头文件 
using namespace std;
int a[30][30];
int dp[30][30][30][30];//记忆化搜索的dp 
int n,m;
int k;
int dfs(int x,int y,int w,int h)//dfs函数 
{
	int cnt=0;//cnt表示该蛋糕上的樱桃数
	for(int i=x+1;i<=x+w;i++)
	{
		for(int j=y+1;j<=y+h;j++)
		{
			if(a[i][j]) cnt++;//统计樱桃数
		}
	}
	if(cnt==0) return 999999999;//如果蛋糕上的樱桃数为0,999999999代表inf 
	if(cnt==1) return 0;//如果蛋糕上的樱桃数为1,直接return 0 
	if(dp[x][y][w][h]!=-1) return dp[x][y][w][h];//如果之前搜过,就不用搜了,直接return掉 
	int ans=2147483647;//ans初值为最大值 
	for(int i=1;i<w;i++)//搜横行 
	{
		ans=min(ans,dfs(x,y,i,h)+dfs(x+i,y,w-i,h)+h);//min一下 
	}
	for(int i=1;i<h;i++)//同上 
	{
		ans=min(ans,dfs(x,y,w,i)+dfs(x,y+i,w,h-i)+w);
	}
	dp[x][y][w][h]=ans;//赋值 
	return ans;
}
int main()
{
	memset(dp,-1,sizeof(dp));//给dp赋初值 
	scanf("%d%d%d",&n,&m,&k);
	int p,q;
	for(int i=1;i<=k;i++)
	{
		scanf("%d%d",&p,&q);
		a[p][q]=1;
	}
	cout<<dfs(0,0,n,m);//dfs一下 
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/chen-1/p/9837728.html
今日推荐