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; }