poj_3250 单调栈

题目大意

    N头牛排成一列,每头牛A都能看到它前面比它矮的牛i,若前面有一个比他高的牛X,则X之前的牛j,A都无法看到。给出N头牛的高度,求出这N头牛可以看到牛的数目的总数。

题目分析

    画图之后,可以很容易看出是典型的单调栈问题。单调栈问题中栈元素一般有两个属性:一是牛的索引位置,二是牛的高度。每次得到一个牛index的高度height之后,都和栈顶元素进行比较,若height > stack[top].height 则直接将(新牛的高度height,新牛的索引index)入栈,否则,弹栈,直到栈顶元素stack[top].height < height,再将(新牛的高度height,新牛的索引index)入栈。 
    在牛A被出栈的时候,可以获得牛A能够看到的牛的个数(即新入栈的牛B的索引index_b - 牛A的索引index_a)。最后记得清空栈元素来获得所有值。

实现(c++)

可以不使用单调栈

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<set>
#include<map>
#include<functional>
#include<algorithm>
using namespace std;
const int kMax = 80005;

//height 数组
int height[kMax];

//从i点向左看,第一个高度等于或者大于height[i]的数组下标
int higher_index[kMax];

long long int solve(int n){
	int j;
	long long result = 0;
	for (int i = 0; i < n; i++){
		j = i - 1;
		while (j >= 0 && height[j] < height[i]){
			j = higher_index[j];
		}
		higher_index[i] = j;
		result += (i - j - 1);
	}	
	return result;
}
int main(){
	int n;
	scanf("%d", &n);
	//题目要求从左向右看,将数组颠倒,然后换个方向,从右向左看,结果是一样的
	for (int i = n - 1; i >= 0; i--){
		scanf("%d", &height[i]);
	}
	long long int result = solve(n);
	printf("%lld
", result);
	return 0;
}

使用单调栈

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define MAX_COW_NUM 80005
int st[MAX_COW_NUM][2];
int gCanSeeNum[MAX_COW_NUM];

int main(){
	int n;
	scanf("%d", &n);
	int height, top = -1;
	long long sum = 0;
	for (int i = 0; i < n; i++){
		scanf("%d", &height);
		while (top >= 0 && st[top][1] <= height){
			gCanSeeNum[st[top][0]] = i - st[top][0] - 1;
			sum += gCanSeeNum[st[top][0]];
			top--;
		}
		top++;
		st[top][0] = i;
		st[top][1] = height;
	}
	while (top >= 0){
		gCanSeeNum[st[top][0]] = n - st[top][0] - 1;
		sum += gCanSeeNum[st[top][0]];
		top--;
	}
	printf("%lld
", sum);
	return 0;
}

 使用单调栈2

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<set>
#include<map>
#include<functional>
#include<algorithm>
using namespace std;
const int kMax = 80005;

//height 数组
int height[kMax];
int mon_stack[kMax];
long long int solve(int n){
	int top = -1;
	long long result = 0;
	for (int i = 0; i < n; i++){
		while (top >= 0 && height[mon_stack[top]] < height[i]){
			top--;
		}
		if (top < 0)
			result += i;
		else
			result += (i - mon_stack[top] - 1);
		mon_stack[++top] = i;
	}
	return result;
}
int main(){
	int n;
	scanf("%d", &n);
	//题目要求从左向右看,将数组颠倒,然后换个方向,从右向左看,结果是一样的
	for (int i = n - 1; i >= 0; i--){
		scanf("%d", &height[i]);
	}
	long long int result = solve(n);
	printf("%lld
", result);
	return 0;
}
原文地址:https://www.cnblogs.com/gtarcoder/p/4835648.html