在这里插入图片描述
UVA1629
定义
UpperLeftUpperLeft为矩形左上角,LowerRightLowerRight为右下角。
dp[UpperLeft.x][UpperLeft.y][LowerRight.x][LowerRight.y]dp[UpperLeft.x][UpperLeft.y][LowerRight.x][LowerRight.y]为由两组坐标确定的矩形区域最少要切割多少长度才能满足要求。
PrefixSum[i][j]PrefixSum[i][j]为从(0,0)到(i,j)的矩形区域一共有多少樱桃。(用于O(1)计算出给定矩形区域内樱桃数量)。
初始化
dp=infdp=inf
转移方程
dp[UpperLeft.x][UpperLeft.y][LowerRight.x][LowerRight.y]=min(dp[UpperLeft.x][UpperLeft.y][i][LowerRight.y]+dp[i+1][UpperLeft.y][LowerRight.x][LowerRight.y]+LowerRight.yUpperLeft.y+1(UpperLeft.xi<LowerRight.x,),dp[UpperLeft.x][UpperLeft.y][LowerRight.x][i]+dp[UpperLeft.x][i+1][LowerRight.x][LowerRight.y]+LowerRight.xUpperLeft.x+1(UpperLeft.yi<LowerRight.y,)dp[UpperLeft.x][UpperLeft.y][LowerRight.x][LowerRight.y]=min(\\ dp[UpperLeft.x][UpperLeft.y][i][LowerRight.y]\\+dp[i+1][UpperLeft.y][LowerRight.x][LowerRight.y]\\+LowerRight.y-UpperLeft.y+1(UpperLeft.x\leq i<LowerRight.x,横着切),\\ dp[UpperLeft.x][UpperLeft.y][LowerRight.x][i]\\+dp[UpperLeft.x][i+1][LowerRight.x][LowerRight.y]\\+LowerRight.x-UpperLeft.x+1(UpperLeft.y\leq i<LowerRight.y,竖着切)
AC代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
int n, m, k;
bool HasCherry[21][21];
int PrefixSum[22][22];
int dp[22][22][22][22];
constexpr static int inf = 0x3f3f3f3f;
struct Point {
	int x, y;
};
bool Input() {
	if (scanf("%d%d%d", &n, &m, &k) == EOF) {
		return false;
	}
	memset(HasCherry, false, sizeof(HasCherry));
	while (k--) {
		int x, y;
		scanf("%d%d", &x, &y);
		HasCherry[x][y] = true;
	}
	return true;
}
void InitPrefixSum() {
	memset(PrefixSum, 0x0, sizeof(PrefixSum));
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			PrefixSum[i][j] = PrefixSum[i - 1][j] + PrefixSum[i][j - 1] - PrefixSum[i - 1][j - 1] + HasCherry[i][j];
		}
	}
}
const int getCherryNumber(const Point& UpperLeft,const Point& LowerRight) {
	return
		PrefixSum[LowerRight.x][LowerRight.y]
		- PrefixSum[LowerRight.x][UpperLeft.y - 1]
		- PrefixSum[UpperLeft.x - 1][LowerRight.y]
		+ PrefixSum[UpperLeft.x - 1][UpperLeft.y - 1];
}
int DP(Point UpperLeft, Point LowerRight) {
	int& Ans = dp[UpperLeft.x][UpperLeft.y][LowerRight.x][LowerRight.y];
	const int&& CherryNumber = getCherryNumber(UpperLeft, LowerRight);
	//樱桃数量为0,不符合题意,返回inf
	if (!CherryNumber) {
		return Ans = inf;
	}
	//不需要切了,返回0
	else if (CherryNumber == 1) {
		return Ans = 0;
	}
	if (Ans != inf) {
		return Ans;
	}
	//横着切,枚举每一种切割方案
	for (int i = UpperLeft.x; i < LowerRight.x; ++i) {
		Ans = min(
			Ans, 
			DP(UpperLeft, { i,LowerRight.y }) 
			+ DP({ i + 1,UpperLeft.y }, LowerRight) 
			+ LowerRight.y - UpperLeft.y + 1
		);
	}
	//竖着切
	for (int i = UpperLeft.y; i < LowerRight.y; ++i) {
		Ans = min(
			Ans,
			DP(UpperLeft, { LowerRight.x,i })
			+ DP({ UpperLeft.x,i + 1 }, LowerRight)
			+ LowerRight.x - UpperLeft.x + 1
		);
	}
	return Ans;
}
int main() {
	int&& Case = 0;
	while (Input()) {
		InitPrefixSum();
		memset(dp, 0x3f, sizeof(dp));
		printf("Case %d: %d\n", ++Case, DP({ 1,1 }, { n, m }));
	}
	return 0;
}
posted on 2020-01-20 16:36  SCU_GoodGuy  阅读(484)  评论(0)    收藏  举报