Description
Input
Output
题目大意:一个N*M的游泳池,要从(1, 1)游到(1, M),每个格子有变速器和钱(都可能为负),到了钱的地方可以拿到那些钱,到了变速器的地方速度就会加上那个变速器的速度。横向速度恒定为1,纵向速度可以改变,每次可以随意+1、-1或不变,变速器影响的也是纵向的速度。每K秒要到水面呼吸一次,求游到(1, M)的最大钱数。其他细节见题目。
思路:首先朴素的DP(如dp[N, M, V, K]的那种)是没法过的,时间复杂度太大了。另辟蹊径,注意到K很小,只有10,而且每次到水面速度会变为0,那么可以利用这一点,dp[i]表示到(1, i)时取得的最大金钱,然后对(1, i)爆搜K步,每次时间复杂度为O(3^K),总复杂度为O(M * 3^K),也不过6 * 10^7。
PS:这题坑爹的地方比较多,来一一细说。
1、每个格子的P (-1000000 <= P <= 1000000),乘个1000绝对爆32位整数,但是人人都用int我也用了int,不知道大家有没看到答案在32位以内反正我是没看到。
2、题目原句:and when reaching a surface cell with a speedo of value Q, Facer's vertical speed becomes Q immediately.
3、翻译一下:当到达水平而且那个格子有一个变速器Q,那么速度变为Q(不知道有没翻译错)
4、按这个说法,如果我所有格子都是V20,就不一定有答案了,题目是没说没答案怎么处理的……
5、重点是我按上面的说法做AC不了,改成到达水面之后速度为0不管那个格子有木有变速器就能AC,WA了几次之后对拍别人的AC代码发现的。
6、然后我看到了这句:All speed changing machines in the surface cells can't work。我承认我没认真看题但也不带这样坑我的啊……
代码(POJ 1219MS):
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 typedef long long LL; 7 8 const int MAXN = 110; 9 const int MAXM = 1010; 10 const int INF = 0x3fff3fff; 11 12 int dp[MAXM]; 13 int mat[MAXN][MAXM]; 14 bool money[MAXN][MAXM]; 15 int n, m, k; 16 17 void dfs(int from, int ti, int tj, int spd, int sum) { 18 if(ti < 1) ti = 1; 19 if(ti > n) ti = n; 20 if(ti == 1 && from != tj) { 21 if(dp[tj] < sum) dp[tj] = sum; 22 return ; 23 } 24 if(tj - from == k || tj == m) return ; 25 if(money[ti][tj]) sum += mat[ti][tj]; 26 else if(ti != 1) spd += mat[ti][tj]; 27 dfs(from, ti + spd - 1, tj + 1, spd - 1, sum); 28 dfs(from, ti + spd , tj + 1, spd , sum); 29 dfs(from, ti + spd + 1, tj + 1, spd + 1, sum); 30 } 31 32 void solve() { 33 dp[1] = 0; 34 for(int i = 2; i <= m; ++i) dp[i] = -INF; 35 for(int i = 1; i < m; ++i) { 36 if(dp[i] == -INF) continue; 37 dfs(i, 1, i, 0, dp[i]); 38 } 39 //for(int i = 1; i <= m; ++i) printf("%d\n", dp[i] + money[1][i] * mat[1][i]); 40 if(money[1][m]) dp[m] += mat[1][m]; 41 printf("%d\n", dp[m]); 42 } 43 44 char lastch = ' '; 45 46 inline char readchar() { 47 while(lastch != 'v' && lastch != '$') 48 lastch = getchar(); 49 return lastch; 50 } 51 52 inline int readint() { 53 int g = 0, l; 54 while(!isdigit(lastch) && lastch != '-') lastch = getchar(); 55 if(lastch == '-') { 56 l = -1; 57 lastch = getchar(); 58 } 59 else l = 1; 60 while(isdigit(lastch)) { 61 g = g * 10 + lastch - '0'; 62 lastch = getchar(); 63 } 64 return g * l; 65 } 66 67 int main() { 68 while(true) { 69 n = readint(); m = readint(); k = readint(); 70 if(n + m + k == 0) break; 71 char c; 72 for(int i = 1; i <= n; ++i) { 73 for(int j = 1; j <= m; ++j) { 74 //scanf(" %c%d", &c, &mat[i][j]); 75 c = readchar(); 76 mat[i][j] = readint(); 77 money[i][j] = (c == '$'); 78 } 79 } 80 solve(); 81 } 82 }
代码(POJ 1922MS):
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 typedef long long LL; 7 8 const int MAXN = 110; 9 const int MAXM = 1010; 10 const int INF = 0x3fff3fff; 11 12 int dp[MAXM]; 13 int mat[MAXN][MAXM]; 14 bool money[MAXN][MAXM]; 15 int n, m, k; 16 17 void dfs(int from, int ti, int tj, int spd, int sum) { 18 if(ti < 1) ti = 1; 19 if(ti > n) ti = n; 20 if(ti == 1 && from != tj) { 21 if(dp[tj] < sum) dp[tj] = sum; 22 return ; 23 } 24 if(tj - from == k || tj == m) return ; 25 if(money[ti][tj]) sum += mat[ti][tj]; 26 else if(ti != 1) spd += mat[ti][tj]; 27 dfs(from, ti + spd - 1, tj + 1, spd - 1, sum); 28 dfs(from, ti + spd , tj + 1, spd , sum); 29 dfs(from, ti + spd + 1, tj + 1, spd + 1, sum); 30 } 31 32 void solve() { 33 dp[1] = 0; 34 for(int i = 2; i <= m; ++i) dp[i] = -INF; 35 for(int i = 1; i < m; ++i) { 36 if(dp[i] == -INF) continue; 37 dfs(i, 1, i, 0, dp[i]); 38 } 39 if(money[1][m]) dp[m] += mat[1][m]; 40 printf("%d\n", dp[m]); 41 } 42 43 int main() { 44 while(scanf("%d%d%d", &n, &m, &k) != EOF) { 45 if(n + m + k == 0) break; 46 char c; 47 for(int i = 1; i <= n; ++i) { 48 for(int j = 1; j <= m; ++j) { 49 scanf(" %c%d", &c, &mat[i][j]); 50 money[i][j] = (c == '$'); 51 } 52 } 53 solve(); 54 } 55 }