HDU -- 免費餡餅(ACM Step: 3.2.8)
阿新 • • 發佈:2018-12-15
一、概述
1、問題描述
在一個長度為10的數軸中,從0到10編號,gameboy站在座標為5的點,此刻時間為0。
已知,每過1秒,在不同的座標點都有可能出現餡餅,並且gameboy每秒鐘只能走1個數軸單位的距離,求在已知餡餅掉落的時間和位置下gameboy可以得到的最多餡餅數,在每個位置可能同時出現多個餡餅。
2、問題連結
3、問題截圖
圖1.1 問題截圖
二、演算法思路
此題和數塔問題類似。
假設t表示當前的時間,即t=0,p表示當前的位置,即p=5。
在t=1時,gameboy可以走到p=4、5、6這三個位置,他要走到哪個呢?他應該走到可以得到最大值的位置,因此需要繼續分析,4、5、6哪個才能得到最大值。現在問題變成了找到t=1時,p=4、5、6這三個位置的最大值中的較大者。
對於4,要求它的最大值,需要在t=2時,從p=3、4、5三個位置中找出最大值,然後加上它自己所帶有的餡餅數。
對於5,要在t=2時,從p=4,5,6中的最大值,並且加上自己的餡餅數。
6也是一樣。
可以發現,最後幾乎要求在所有可能的t,以及所有可能的位置p,中可以得到的最大值問題。
由於最後一層可以得到的最大值就是它們本身的餡餅數,因此可以從最下層往上構造,這樣同時可以保證對每個子問題只求過一次。
也可以使用遞迴,假設問題求在(t=0,p=5)的最大值,那麼它可以轉變為(1,4),(1,5),(1,6)三個字問題,即可以使用3次遞迴。
要求解(1,4),即求解(2,3),(2,4),(2,5)
要求解(1,5),即求解(2,4),(2,5),(2,6)
要求解(1,6),即求解(2,5),(2,6),(2,7)
可以發現用遞迴會使得同一個子問題如(2,5)要被計算多次,所以使用從下向上的解法將避免這個問題。
三、演算法實現
#include <cstdio> // for printf, scanf #include <array> using std::array; const int COORDINATE_NUMS = 11; const int MAXSIZE = 1e5; array<array<int, COORDINATE_NUMS>, MAXSIZE> data; // input 2d-array, data[i][j] indicating whether time i and position j have input array<array<int, COORDINATE_NUMS>, MAXSIZE> ans; // ans for answer, result 2d-array that assume gameboy begin at time i and position j int input(int); // for input data int calculate(int); // for calculate result void print(int); // for print result int main() { int n; while (1){ scanf("%d", &n); if (n == 0) break; n = input(n); n = calculate(n); print(n); // clear array for next input data = array<array<int, COORDINATE_NUMS>, MAXSIZE>(); ans = array<array<int, COORDINATE_NUMS>, MAXSIZE>(); } return 0; } // get max value of 2 integer int get_2_max(int a, int b) { return (a>b)?a:b; } // get max value of 3 integer int get_3_max(int a, int b, int c) { int ret = a; if(b > ret) ret = b; if(c > ret) ret = c; return ret; } // read input data, return the depth of digit tower int input(int n) { int x, t; int ret = 0; for (int i=0; i<n; ++i){ scanf("%d%d", &x, &t); ++data[t][x]; if (t > ret) ret = t; } return ret; } // calculate the result, T indicate the max value of input time int calculate(int T) { int t = T; // t indicate array index of the current time // max vale of the last time of position i is itself for (int i=0; i<COORDINATE_NUMS; ++i) ans[t][i] = data[t][i]; --t; // done with time t, t indicate to prior time now for (int i=t; i>=0; --i){ // the max value of position 0 and 10 of time i depend on positon 0, 1 and 9, 10 of time i+1, respectively ans[i][0] = get_2_max(ans[i+1][0], ans[i+1][1]) + data[i][0]; ans[i][10] = get_2_max(ans[i+1][9], ans[i+1][10]) + data[i][10]; // other positons depends on three value of time i+1 for (int j=1; j<COORDINATE_NUMS-1; ++j) ans[i][j] = get_3_max(ans[i+1][j-1], ans[i+1][j], ans[i+1][j+1]) + data[i][j]; } return ans[0][5]; } // print the result void print(int n) { printf("%d\n", n); }