// Weights and Measures (重量和力量)// PC/UVa IDs: 111103/10154, Popularity: C, Success rate: average Level: 3// Verdict: Programming Challenges - Solved, UVa - Accepted// Submission Date: 2011-10-12// UVa Run Time: 0.080s//// 著作權(C)2011,邱秋。metaphysis # yeah dot net//// I know, up on top you are seeing great sights,// But down at the bottom, we, too, should have rights.// We turtles can't stand it. Our shells will all crack!// Besides, we need food. We are starving!" groaned Mack.//// Yertle the Turtle, Dr.Seuss//// [Problem Description]// A turtle named Mack, to avoid being cracked, has enlisted your advice as to// the order in which turtles should be stacked to form Yertle the Turtle’s throne.// Each of the 5,607 turtles ordered by Yertle has a different weight and strength.// Your task is to build the largest stack of turtles possible.//// [Input]// Standard input consists of several lines, each containing a pair of integers// separated by one or more space characters, specifying the weight and strength// of a turtle. The weight of the turtle is in grams. The strength, also in grams,// is the turtle’s overall carrying capacity, including its own weight. That is,// a turtle weighing 300 g with a strength of 1,000 g can carry 700 g of turtles// on its back. There are at most 5,607 turtles.//// [Output]// Your output is a single integer indicating the maximum number of turtles that// can be stacked without exceeding the strength of any one.//// [Sample Input]// 300 1000// 1000 1200// 200 600// 100 101//// [Sample Output]// 3//// [解題方法]// 開始以為是很簡單的 DP 題,把烏龜按可承重重量增序排列,若可承重重量相同,則體重輕的排上面,然後// DP 求能得到的最大高度。程式在 Programming Challenges 倒是通過了,但是在 UVa 上是 WA。閱// 讀了 UVa BBS 上的文章,才發現之所以在 PC 上通過是因為其測試資料太弱(汗...)。//// 先分析一下按可承重重量增序排列,若可承重重量相同,體重輕的排上面的方法為什麼不可行。可// 承重重量除了給出這隻烏龜還能承重的重量外,不能給出更多資訊了,如兩隻烏龜,重量和力量如下://// (1)10 50// (2)100 120//// 如果按照上述的排序方法烏龜(1)應該排在下方,(2)排在上方,能形成的烏龜塔最高為 1,但是實際上// 若(2)在下,(1)在上,是能形成高度為 2 的烏龜塔的。所以按這種排序方法是不能達到烏龜順序的最// 優子結構的,所以也就不能保證一定獲得最優解。//// 若按重量增序,重量相同按力量增序的順序排列烏龜,也會得到錯誤的答案,因為沒有考慮到烏龜的可承重// 重量,反例如下://// (1)10 1000// (2)20 1000// (3)30 40//// 排好序後烏龜塔的最高高度為 2,實際上應該是 3,只需將(3)放在最上面即可。//// 若按力量增序排列,力量相同按體重增序排列,從第一隻烏龜開始處理,設當前新增加的烏龜為 i,從 1 到// i - 1 搜尋總重量小於烏龜 i 的可承重重量,且高度能增加的烏龜 j,更新烏龜 i 的總承重重量和能堆// 疊的最大高度,使用這種方法,對於一般的測試資料,都能得到正確的答案,但是對於如下測試資料,卻不能// 得到正確的答案(之前我就是使用這種方法)://// (1)101 101// (2)100 201// (3)99 300// (4)98 301// (5)5 302//// 前述演算法能得到的最大高度是 3,實際上將(2),(3),(4),(5)堆疊起來可以得到高度為 4 的烏// 龜塔,為什麼演算法失效了?因為在第二步處理烏龜(2)的時候,因為烏龜(1)能放在烏龜(2)上,故烏龜// (2)擁有了最大高度 2,從而在處理後續烏龜時,(2)不能作為單獨烏龜放置在其他烏龜上,只能是和(1)// 做為一個整體來放置,所以需要記錄能達到高度 K 的烏龜塔時,烏龜的最小總重量,這樣在構建烏龜塔時,// 總是選擇當前能堆疊最高且總重量最小的烏龜,才有可能構建更高的烏龜塔。//// 那麼是否可以按力量來進行排序?答案是肯定的,假設有兩隻烏龜,重量和力量分別為 W1,S1,W2,S2,// 且有 S1 <= S2,那麼排序如下://// W1 S1// W2 S2//// 若力量為 S1 的烏龜能支撐起包括 W2 在內的烏龜重量,則有 S1 >= (W1 + W2),因為有 S2 >= S1// 則力量為 S2 的烏龜總是同樣能支撐起來,但是反過來就不一定了,即 S2 >= (W1 + W2),不一定有// S1 >= (W1 + W2),故按力量來排序總是不會改變最優結構的。//// 綜上所述,使用一個二維數組記錄使用前 i 只烏龜形成高度為 h 的塔時的最小總重量,設為 minWeight// [h][i],有以下轉移方程://// minWeight[h][i] = min{minWeight[h][i - 1],minWeight[h - 1][i - 1] + weight[i]}//// 其中第二個是有條件的,即 minWeight[h - 1][i - 1] + weight[i] <= strength[i]。同樣的,// 因為有較多的烏龜,若使用二維數組因數組很大而會引起段錯誤,可以使用一維滾動數組來代替最佳化空間使// 用以避免出現因分配過多記憶體導致段錯誤。為什麼可以用一維數組來最佳化,這是題目的轉移方程決定的,在// 最開始的時候,烏龜數目為 0,形成高度為 0 的烏龜塔時,最小總重量當然為 0,但是對於從 1 到烏龜// 總數的高度,是不可能堆疊成的,可設其最小總重量為一 MAXINT 值來標記。此時數組元素如下://// minWeight[0][0] 0// minWeight[1][0] MAXINT// minWeight[2][0] MAXINT// ... ...// minWeight[N][0] MAXINT//// 假設需要計算烏龜數目為 1 時,形成的高度為 1 的烏龜塔最小總重量時,則根據轉移方程,有://// minWeight[1][1] = min{minWeight[1][0],minWeight[0][0] + weight[1]}//// 當然第二個值是有條件的(這裡假設滿足條件),從數組的元素可以知道,minWeight[1][0] 已經存在於// 數組中,minWeight[0][0] 也存在於數組中,最後計算得到的值 minWeight[1][1],所存放的位置與// minWeight[1][1] 行標號相同,只不過列標號增加 1,此後列為 0 的元素就不會被使用了,那麼可以直// 接省略掉列標號,變成一維數組://// minWeight[0] minWeight[1] minWeight[2] ... minWeight[N]// 0 MAXINT MAXINT ... MAXINT//// 只不過在計算的時候,為了不覆蓋前一次計算的值,每次都從最後一個元素開始使用轉移方程往前計算即可。// 前面的 UVa 10069 Distinct Subsequences 也可以使用的同樣的方法來最佳化。#include <iostream>#include <algorithm>using namespace std;#define MAXN 5610#define MAXINT (1 << 20)class turtle{public:int weight;int strength;bool operator<(const turtle &other) const{// 力量大的的在下方。if (strength != other.strength)return strength < other.strength;// 若力量相同,則重的烏龜在下方。return weight < other.weight;};};int main(int ac, char *av[]){turtle turtles[MAXN];int minWeight[MAXN];int nTurtles = 1, weight, strength;while (cin >> weight >> strength){if (weight > strength)continue;turtles[nTurtles++] = (turtle){weight, strength};}// 按力量和自身重量排序。sort(turtles + 1, turtles + nTurtles);nTurtles--;// 賦初值,若為 MAXINT 則不可能形成高度為 h 的烏龜塔。minWeight[0] = 0;for (int h = 1; h <= nTurtles; h++)minWeight[h] = MAXINT;// DP 找最大高度。int answer = 1;for (int i = 1; i <= nTurtles; i++)for (int h = nTurtles; h >= 1; h--){if (minWeight[h - 1] + turtles[i].weight <= turtles[i].strength)minWeight[h] = min(minWeight[h], minWeight[h - 1] + turtles[i].weight);if (minWeight[h] < MAXINT)answer = max(answer, h);}cout << answer << endl;return 0;}