Codeforces Round #669 (Div. 2) D. Discrete Centrifugal Jumps(dp、单调栈)

Codeforces Round #669 (Div. 2) D. Discrete Centrifugal Jumps(dp、单调栈)

1407 D Discrete Centrifugal Jumps

题意:给定n个楼高,要求从1位置跳到n位置。问最少的跳的次数
合法跳跃 i − > j i->j i>j

  1. i + 1 = j i+1=j i+1=j
  2. m a x ( a i + 1 , a i + 2 , . . . , a j − 1 ) < m i n ( a i , a j ) max(a_{i+1},a_{i+2},...,a_{j-1})<min(a_{i},a_{j}) max(ai+1,ai+2,...,aj1)<min(ai,aj)
  3. m a x ( a i + 1 , a i + 2 , . . . , a j − 1 ) > m i n ( a i , a j ) max(a_{i+1},a_{i+2},...,a_{j-1})>min(a_{i},a_{j}) max(ai+1,ai+2,...,aj1)>min(ai,aj)

思路:
首先题目要求最少跳跃次数,而且题意判断出前面的最优状态不影响之后的,想到dp
当时第一感觉是用单调栈找到当前位置 j j j处向左的第一个大于等于/小于等于他的位置然后跳跃,每次都是找最长的位置。主要代码如下:

for (int i = 1; i <= n; i++)dp[i] = maxn;
	dp[0] = 0; dp[1] = 0;
	for (int i = 1; i <= n; i++) {
    
    
		cin >> a[i];
		//向左找到第一个小于等于他的位置下标,其余位置的h都大于
		while (sma.size() && a[sma.top()] > a[i]) sma.pop();
		if (sma.empty()) maxx[i] = 0;
		else maxx[i] = sma.top();
		sma.push(i);
 		//向左找到第一个大于等于他的位置下标,其余位置的h都小于
		while (smin.size() && a[smin.top()] < a[i])smin.pop();
		if (smin.empty())minn[i] = 0;
		else minn[i] = smin.top();
		smin.push(i);
 
		if (i == 1)continue;
		dp[i] = dp[i - 1] + 1;
		if (minn[i]) dp[i] = min(dp[i], dp[minn[i]] + 1);
		if (maxx[i]) dp[i] = min(dp[i], dp[maxx[i]] + 1);
	}
	cout << dp[n] << endl;

但是这个思路不太对,每次都最长不一定是最优解,所以一直wa5。
其实就是在dp的时候对于每个可行的解都转移试试看,最后输出 d p n dp_{n} dpn就可,代码如下

int a[maxn], maxx[maxn], minn[maxn], dp[maxn];//记录当前位置向左,第一个大于等于/小于等于他的下标
stack<int> sma, smin;
int main()
{
    
    
	int ans = maxn;
	int n, tt;
	//int Min = maxn, Max = 0;//记录2-当前位置的最大/最小值
	cin >> n;
	for (int i = 1; i <= n; i++)dp[i] = maxn;
	dp[0] = 0; dp[1] = 0;
	cin >> a[1];
	sma.push(1);
	smin.push(1);
	for (int i = 2; i <= n; i++) {
    
    
		cin >> a[i];
		dp[i] = dp[i - 1] + 1;
		//向左找第一个小于等于i的下标,中间都大于他
		while (sma.size() && a[sma.top()] >= a[i]) {
    
    
			tt = a[sma.top()];
			sma.pop();
			if (a[i] < tt&&sma.size()) dp[i] = min(dp[i], dp[sma.top()] + 1);
		}
		sma.push(i);
		//向左找第一个大于等于i的下标,中间都小于他
		while (smin.size() && a[smin.top()] <= a[i]) {
    
    
			tt = a[smin.top()];
			smin.pop();
			if (a[i] > tt&&smin.size()) dp[i] = min(dp[i], dp[smin.top()] + 1);
		}
		smin.push(i);
	}
	cout << dp[n] << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44986601/article/details/108497128