1. 程式人生 > >hdu 免費餡餅

hdu 免費餡餅

題目,點選開啟
我認為可以用兩個陣列儲存,a與f設a[i][j]為第i秒的j位置掉下的餡餅數量,
f[i][j]為第i秒在j位置接餡餅最多可以接到的最多餡餅數量。
然後就是關於移動。因為gameboy一秒移動一個單位,故一秒可到位置是
f[i-1][j-1]
f[i-1][j]
f[i-1][j+1]
自己複習了dp後,自己也學會了一點,發現每一個演算法都有狀態轉移方程,
這題應該是一個揹包,所以,在思索了30多分鐘(可憐的孩子)後,終於
想出來了此題的狀態轉移方程:
f[i][j]=max(f[i-1][j-1],f[i-1][j],f[i-1][j+1])+a[i][j];
但是,還有一種簡單的方法,

數塔問題都聽過吧,這題算是dp與遞推的入門題,採用動態規劃自底向上計算,如果我們要知道所走之和最大,那麼最後一步肯定是走最後一排數其中一個,向上退,倒數第二步肯定走最後一排數對應的倒數第二排最大的一個(將最後對應最後步走的最大的數加起來存在倒數第二步的陣列中)再向上推,一直推到最上面的第0步,那麼dp[0][0]最後所存的結果一定是最大的。
那這題也是一樣的,把秒數當行,距離當列,先儲存,在數塔,解決。
標碼

#include <iostream>  
#include <cstdio>  
#include <algorithm>  

using namespace
std; const int maxn = 100005; int a[maxn][12]; int f[maxn][12]; int maxT; int dp(){ int i; int j; int maxSum = -9; f[1][4] = a[1][4]; f[1][5] = a[1][5]; f[1][6] = a[1][6]; for(i = 2 ; i <= maxT ; ++i){ for(j = 0 ; j < 11 ; ++j){ f[i][j] = f[i-1
][j]; if(j > 0){ f[i][j] = max(f[i][j],f[i-1][j-1]); } if(j < 10){ f[i][j] = max(f[i][j],f[i-1][j+1]); } f[i][j] += a[i][j]; } } for(i = 1 ; i <= maxT ; ++i){ for(j = 0 ; j < 11 ; ++j){ if(maxSum < f[i][j]){ maxSum = f[i][j]; } } } return maxSum; } int main(){ int n; while(scanf("%d",&n)!=EOF,n){ memset(a,0,sizeof(a)); memset(f,0,sizeof(f)); int i; for(i = 1 ; i <= n ; ++i){ int x,t; scanf("%d%d",&x,&t); a[t][x]++; maxT = max(maxT,t); } printf("%d\n",dp()); } return 0; }

注:不用scanf好像超時。