单调栈解决木板倒水问题

题目:

地上从左到右竖立着n块木板,从1到n依次 编号,如下图所示。我们知道每块木板的高度,在第n块木板右侧竖立着一块高度无限大的木板,现对每块木板依次做如下的操作:对于第i块木板,我们从其右侧开始倒水,直到水的高度等于第i块木板的高度,倒入的水会淹没ai块木板(如果木板左右两侧水的高度大于等于木板高度即视为木板被淹没)。求n次操作后,所有ai的和是多少。如图所示,在第4块木板右侧倒水,可以淹没第5块和第6块一共a4=2块木板。

单调栈解决木板倒水问题_第1张图片

 

解答:

#include 
#include 

#define ERROR 0
#define OK 1

typedef struct Node {
	int id, height;
} Node;

typedef struct Stack {
	Node *elements;
	int max_size, top_index;
} Stack;

void init(Stack *s, int length) {
	s->elements = (Node *)malloc(sizeof(Node) * length);
	s->max_size = length;
	s->top_index = -1;
}

int push(Stack *s, Node element) {
	if (s->top_index >= s->max_size - 1) {
		return ERROR;
	}
	s->top_index++;
	s->elements[s->top_index] = element;
	return OK;
}

int pop(Stack *s) {
	if (s->top_index < 0) {
		return ERROR;
	}
	s->top_index--;
	return OK;
}

Node top(Stack *s) {
	return s->elements[s->top_index];
}

int empty(Stack *s) {
	if (s->top_index < 0) {
		return 1;
	}
	else {
		return 0;
	}
}

void clear(Stack *s) {
	free(s->elements);
	free(s);
}

int main() {
	int n, ans = 0;
	scanf("%d", &n);
	Stack *stack = (Stack*)malloc(sizeof(Stack));
	init(stack, n);
	Node temp;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &temp.height);
		temp.id = i;
		while (!empty(stack) && top(stack).height <= temp.height) {
			ans = ans + i - top(stack).id - 1;
			pop(stack);
		}
		push(stack, temp);
	}
	while (!empty(stack)) {
		ans = ans + n + 1 - top(stack).id - 1;
		pop(stack);
	}
	printf("%d\n", ans);
	clear(stack);
	return 0;
}

 

 分析:

最开始并没有理解为什么ans的求和是用

ans = ans + i - top(stack).id - 1;

这样的语句,因为我错把题目理解成了 从某块木板右侧加水,加到与自身齐平时就停止,然后另从该木块右侧第一个不低于它的木块开始继续加水。这样加水的次数的会小于n,不符合题设。

题目真正的意思可以理解为,加水至与自身齐平并统计被淹没木板数量后,就把水倒掉,从该木板右侧第一块木板开始继续加水。

这样,就可以解释在相加求和时出现的“重复计算”问题了。

你可能感兴趣的:(计蒜客,单调栈,数据结构)