Of course you have heard the famous task about Hanoi Towers, but did you know that there is a special factory producing the rings for this wonderful game? Once upon a time, the ruler of the ancient Egypt ordered the workers of Hanoi Factory to create as high tower as possible. They were not ready to serve such a strange order so they had to create this new tower using already produced rings.
There are n rings in factory's stock. Thei-th ring has inner radius ai, outer radius bi and height hi. The goal is to select some subset of rings and arrange them such that the following conditions are satisfied:
- Outer radiuses form a non-increasing sequence, i.e. one can put the j-th ring on the i-th ring only ifbj ≤ bi.
- Rings should not fall one into the the other. That means one can place ring j on the ring i only if bj > ai.
- The total height of all rings used should be maximum possible.
The first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the number of rings in factory's stock.
The i-th of the next n lines contains three integers ai,bi andhi (1 ≤ ai, bi, hi ≤ 109,bi > ai) — inner radius, outer radius and the height of thei-th ring respectively.
Print one integer — the maximum height of the tower that can be obtained.
题目的意思就是用环来搭汉诺塔,每个环有内径a,外径b和高h,搭的时候上面环外径的要比下面的小,但是不能掉下去,也就是上面的环外径要比下面的环内径大。输入一些环的内径,外径,高度,求用这些环能搭的汉诺塔的最大高度。
主要用排序+动态规划,按tutorial的思路写了一遍。首先做一个处理,所有的外径一样的环可以看作把这些环叠在一起变成一个环,这是一定可以做到的,这些环的内径一定小于它们的外径,所以高度是这些环高度的总和,内径取最小的,就是相当于把内径最小的环放在最上面。将这些环按外径从大到小,保证在后面的环一定是后放上去的。然后就是动态规划,用dp[i]表示最上面的环是第i个环所能达到的最大高度,很直接的想法就是看第i个环能不能放到前面的i-1个环上,如果能放到某个环j上,新的高度就是dp[j]+第i个环的高度。取最大的为dp[i](前面i-1个上面都不能放,dp[i]就是环i的高度)。最后的答案就是所有dp[i]中最大的。(超时,只过了十几个样例)
可以再优化,注意到,如果第k个环可以放到第i个环和第j个环上(i < j < k),那么第j个环一定可以放到第i个环上(ring[i].a < ring[k].b, ring[k].b < ring[j].b, 于是ring[i].a < ring[j].b),所以如果环k可以放到第i和第j个环上(i<j),那么一定有dp[j] >= dp[i],所以求dp[k]的时候动第第k-1个环往前找,找到的第一个满足ring[j].a < ring[k].b的j就是最大的。(还是超时,过了40多个样例)
继续优化,越往上放的环越小,所以那些不能放在第i个环下面的一定也不能放在第i个环之后的所有环下面。tutorial里面给了一种用栈的做法,可以被放在下面的环留在栈里面,不能被放在下面的环出栈。还有一种是维持一个按内径大小排好序的序列,想法类似,内径大的那些不要管。
#include<iostream>
#include<vector>
#include<algorithm>
#include<stack>
using namespace std;
struct ring {
int a, b, h;
bool operator<(const ring& r) {
return this->a < r.a;
}
};
bool cmp(ring r1, ring r2) {
return r1.b > r2.b;
}
int main() {
int n; cin >> n;
vector<ring> rings;
for (int i = 0; i < n; i++) {
ring r; cin >> r.a >> r.b >> r.h;
rings.push_back(r);
}
ring what; what.b = -1;
rings.push_back(what);
sort(rings.begin(), rings.end(), cmp);
vector<ring> temp;
ring r = rings[0];
for (int i = 1; i < n + 1; i++) {
if (rings[i].b == rings[i - 1].b) {
r.a = r.a < rings[i].a ? r.a : rings[i].a;
r.h += rings[i].h;
}
else {
temp.push_back(r);
r = rings[i];
}
}
int n2 = temp.size();
vector<long long> dp(n2, 0);
dp[0] = temp[0].h;
stack<int> satisfy;
satisfy.push(0);
for (int i = 1; i < n2; i++) {
/*long long m = temp[i].h;
int j;
for (j = i - 1; j >= 0; j--) {
if (temp[j].a < temp[i].b) {
if (dp[j] + temp[i].h > m) {
m = dp[j] + temp[i].h;
}
break;
}
}
dp[i] = m;*/
while (!satisfy.empty()) {
if (temp[satisfy.top()].a >= temp[i].b) satisfy.pop();
else break;
}
if (!satisfy.empty()) dp[i] = dp[satisfy.top()];
dp[i] +=temp[i].h;
satisfy.push(i);
}
long long m = 0;
for (int i = 0; i < n2; i++) {
if (dp[i] > m) m = dp[i];
}
cout << m << endl;
}