【洛谷】【P2101 命运石之门的选择】

题目描述

在某一条不知名世界线的冈伦今天突然接到了一条dmail,上面说世界线将会发生巨大变动,未来的他无论如何都无法扭转这种变动回到原来的世界线。而世界线变动的原因是现在的他不久后错过了与助手的约会。他约好要和助手去约会,但是在去约会之前,由于一直拖欠房租,房东大叔要求他帮忙完成一幅画的上色,然而他没有以最快的速度完成这个任务,导致他错过了与助手的约会,从而导致世界线的剧变。现在到了拯救世界的时候,由于冈伦并不擅长画画,于是他找到了同样不擅长画画的你来帮他解决这个问题(这是命运石之门的选择)。不管怎样现在拯救世界的重任交到了你的手上,而你虽然不擅长画画,但是你可以使用编程来帮助你解决这个问题。

这幅画十分抽象:它由N个宽度为1高度为Hi的矩形组成,矩形并排排列,相邻的矩形间没有空隙,初始情况下每个矩形都是没有颜色的。你有一个宽度为1的刷子,你可以竖直或水平的刷,每次使用刷子,你的刷子都必须保证一直全部处于矩形中,即不能刷到矩形以外的地方去,当然你每次刷的时候也不能拐弯。你每刷一次,要花费1的时间,这和刷的长度无关,比如你可以从最左边刷到最右边(当然是不经过矩形以外的部分),这也只花费1的时间。你的目的是将全部的矩形都涂满颜色。请输出这个最短的时间,以便冈伦决定是自己来完成这个任务还是让你来做苦力。

输入输出格式

输入格式:

第1行:一个正整数N,表示矩形的个数。

接下来N个正整数Hi,表示第i个矩形的高度。

输出格式:

一个整数,表示最少花费的时间。

输入输出样例

输入样例#1:

5
2 2 1 2 1

输出样例#1:

3

说明

【数据规模】

30% N<=20, Hi<=100

60% N<=100, Hi<=1000

100% N<=5,000, Hi<=10^9

很冷门的一道题,题解几乎没有,所以……

刚看到时以为是DP,但考虑到后效性感觉DP解不了,于是便利用分治的思想乱搞了出来,下面详细叙述过程:

对于题中给我们的图形,显然最小次数不会超过n,那么我们考虑小于n的刷法,就是横着刷。

但具体要怎么做呢?

自己画图观察一下能够发现,我们可以把不规则的图形划分为大小不同的矩形,对于一个矩形,我们很容易确定要横着还是竖着,就是长和宽嘛。

具体实现的话需要写一个函数,用来求当前区间的最优解。在函数中,我们可以先找最矮的高度,以此确定矩形。找到矩形之后还有其它不规则的图形,这时可以用一个temp变量统计这些的最优解,在求解最优解时只需再次调用该函数即可。

需要注意的就是在处理其他不规则图形时,一定要记得减去已经被涂改的地方,就是已经确定的规则矩形的部分。

CODE

#include<iostream>
#include<cstdio>
using namespace std;

const int N = 5e3+10;
int n, h[N];

int dp(int begin, int end, int last) {
	if (begin == end) return 1;
	int i, temp = 0, mins = 0x3f3f3f3f;
	for (i = begin; i <= end; i++)
		mins = min(mins, h[i]);
	for (i = begin; i <= end; i++) {
		if (h[i] > mins) {
			int j;
			for (j = i; h[j+1]>mins&&j<end; j++);
			temp += dp(i, j, mins);
			i = j;
		}
	}
	return min(mins+temp-last, end-begin+1);
}

int main() {
	scanf("%d", &n);
	int i;
	for (i = 1; i <= n; i++)
		scanf("%d", &h[i]);
	printf("%d", dp(1, n, 0));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38234381/article/details/81235410
今日推荐