POJ 3214 Heap 动态规划法例题

POJ 3214 Heap 动态规划法题解

Description

A (binary) heap is an array that can be viewed as a nearly complete binary tree. In this problem, we are talking about max-heaps.

A max-heap holds the property that for each node than the root, it’s key is no greater than its parent’s. Upon this we further require that for every node that has two children, key of any node in the subtree rooted at its left child should be less than that of any node in the subtree rooted at its right child.

Any array can be transformed into a max-heap satisfying the above requirement by modifying some of its keys. Your task is find the minimum number of keys that have to be modified.

Input

The input contains a single test case. The test case consists of nonnegative integers distributed on multiple lines. The first integer is the height of the heap. It will be at least 1 and at most 20. Then follow the elements of the array to be transformed into a heap described above, which do not exceed 109. Modified elements should remain integral though not necessarily nonnegative.

Output

Output only the minimum number of elements (or keys) that have to be modified.

Sample Input

3
1
3 6
1 4 3 8

Sample Output

4

Hint

   1                 10
  / \               /  \
 3   6    =====>   3    9
/ \ / \           / \  / \
1 4 3 8           1 2  4 8

Source

POJ Monthly--2007.04.01, czh

本题虽然知道是动态规划法,但是建模真的好难。

这里是要把二叉树转换成为数组,然后求最长非递减子序列的。

还需要注意处理其中的大于和大于等于的区别,这样建模的难度真的很高呢。

#include <stdio.h>
#include <vector>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <limits.h>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;

const int MAX_N = 1 << 20 | 1;
int tree[MAX_N], AN;//AN是arr的元素个数, tree下标从1开始
int arr[MAX_N], id;//arr下标从0开始
inline int lSon(int rt) { return rt << 1; }
inline int rSon(int rt) { return rt << 1 | 1; }

void postOrderToArr(int rt, int &span)//因为l<r,故此需要确保条件成立,就可以改成l <= r-1,使用span来确保所有的子树都l<=r-1
{
	if (lSon(rt) <= AN) postOrderToArr(lSon(rt), span);
	if (rSon(rt) <= AN) postOrderToArr(rSon(rt), ++span);
	arr[id++] = tree[rt] - span;
}

int biGetIndex(int low, int up, int val)
{
	while (low <= up)
	{
		int m = low + ((up-low)>>1);
		if (arr[m] > val) up = m-1;
		else low = m+1;
	}
	return low;
}

int getLIS()
{
	int cur = 0;
	for (int i = 1; i < AN; i++)
	{
		if (arr[i] >= arr[cur]) arr[++cur] = arr[i];//这里只是小小的优化,其实可以不用if else判断
		else
		{
			arr[biGetIndex(0, cur, arr[i])] = arr[i];
		}
	}
	return cur+1;
}

int main()
{
	int N;
	AN = 0;//arr 下标从1开始
	scanf("%d", &N);
	int a;
	while (~scanf("%d", &a))
	{
		tree[++AN] = a;
	}
	/*这样计算有误???
	for (int i = 0; i < N; i++)
	{
		int j = 1 << i;
		for (int k = 0; k < j; k++)
		{
			scanf("%d", tree + (++AN));
		}
	}*/
	id = 0;
	int span = 0;
	postOrderToArr(1, span);
	printf("%d\n", AN-getLIS());
	return 0;
}