# Facer is learning to swim

问题描述 :

In the new game, a robot named “Facer” is swimming in a pool. The pool can be considered as a vertical N×M grid. The coordinates of the top-left cell is (1,1), and the coordinates of the bottom-right cell is (N,M). Cells in the top rows are called “surface cells”, and all other cells are called “under water cells”.

Facer starts swimming from the top-left cell (1,1) and must arrive at the top-right cell (1,M). He has a constant horizontal speed of 1 per second, and a vertical speed of v per second. v is always integer and can be changed. If v is positive, it means Facer is moving down; and if v is negative, it means Facer is moving up. So if Facer is at cell (x,y) now , he will arrive at cell (x+v,y+1) after a second. Be careful that if x+v>N, Facer will get to cell (N,y+1) because he cannot move down anymore and of course if x+v<1, Facer will get to cell (1,y+1) because he cannot fly. Please remember that all the “under water cells” in the right-most column are poisonous. If Facer goes into those cells, he will die.

The capacity of Facer’s oxygen bottle is limited, and when Facer gets into a surface cell, the oxygen bottle is refilled automatically. Facer has to refill his oxygen bottle every K seconds, which means that during the time between two refillings, Facer can only pass at most K-1 under water cells in the horizontal direction.

In every cell, there is either a “speed changing machine” or a “money box” (can’t be both). Every speed changing machine has a value T and every money box has a value P.

You have got enough number of devices called “speedo”. Every speedo has a value Q which is 1 or -1. You can put your speedos in any cells, but you can put at most one speedo in a cell.

When Facer reaches a cell, the speed changing machine of value T in that cell (if there is one) will change his vertical speed by T, and the speedo of value Q in that cell (if there is one) will change his vertical speed by Q. For example, if Facer’s vertical speed is v when he arrives at a cell with a speed changing machine of value T and a speedo of value Q, his vertical speed will be changed to v + T + Q immediately. There are three more things you need to know about speed changing:

1. All speed changing machines in the surface cells can’t work.

2. When reaching a surface cell without a speedo, Facer’s vertical speed becomes zero immediately; and when reaching a surface cell with a speedo of value Q, Facer’s vertical speed becomes Q immediately.

3. When reaching a bottom cell, though Facer can’t go down any more, his vertical speed will NOT be changed unless there is a speedo or a speed changing machine in that cell. It’s maybe sound a little bit weird but Facer really is such a weird guy.

When arriving at a cell with a money box of value P, Facer gets P dollars (In fact, if P is negative, Facer loses |P| dollars). Facer’s total amount of money can be negative — that means Facer owes some money to the pool’s owner.

You task is deploying your speedos in a smart way before Facer starts swimming, so Facer can get money as much as possible when he arrives at cell (1,M). Facer’s initial vertical speed is zero and if you put a speedo in the cell (1,1), it will change Facer’s initial vertical speed.

输入:

The first line contains three integers N,M and K (1<=N<=100, 1<=M<=1000, 1<=K<=10), tells the size of the pool and Facer must refill the oxygen bottle every K seconds.

Following are N lines describing the cells by top to bottom order. Each line contains M elements, separated by blanks, telling the information about the cells of a row, by left to right order. There are only two kinds of elements:

1. a char “v” followed by an integer T, meaning that there is a “speed changing machine” of value T (-20<=T<=20) in the correspondent cell.

2. a char “$” followed by an integer P, meaning that there is a “money box” of value P (-1000000<=P<=1000000) in the correspondent cell.

输出:

The first line contains three integers N,M and K (1<=N<=100, 1<=M<=1000, 1<=K<=10), tells the size of the pool and Facer must refill the oxygen bottle every K seconds.

Following are N lines describing the cells by top to bottom order. Each line contains M elements, separated by blanks, telling the information about the cells of a row, by left to right order. There are only two kinds of elements:

1. a char “v” followed by an integer T, meaning that there is a “speed changing machine” of value T (-20<=T<=20) in the correspondent cell.

2. a char “$” followed by an integer P, meaning that there is a “money box” of value P (-1000000<=P<=1000000) in the correspondent cell.

样例输入:

5 10 3 $81 $47 $3 $0 $82 $31 $89 v0 $97 v-1 $14 $94 v1 v-1 v1 $106 v1 v0 v-1 v0 $93 $105 v-1 $219 v0 v0 v-1 v1 $225 v1 v0 $160 v1 v1 $348 $120 $240 $392 $280 $172 $305 $455 $140 v-1 $455 v0 v-1 v0 v1 $410 0 0 0

样例输出:

430

Description

In the new game, a robot named “Facer” is swimming in a pool. The pool can be considered as a vertical N x M grid. The coordinates of the top-left cell is (1,1), and the coordinates of the bottom-right cell is (N, M). Cells in the top rows are called “surface cells”, and all other cells are called “under water cells”.

The capacity of Facer’s oxygen bottle is limited, and when Facer gets into a surface cell, the oxygen bottle is refilled automatically. Facer has to refill his oxygen bottle every K seconds, which means that during the time between two refillings, Facer can only pass at most K – 1 under water cells in the horizontal direction.

In every cell, there is either a “speed changing machine” or a “money box” (can’t be both). Every speed changing machine has a value T and every money box has a value P.

You have got enough number of devices called “speedo”. Every speedo has a value Q which is 1 or -1. You can put your speedos in any cells, but you can put at most one speedo in a cell.

When Facer reaches a cell, the speed changing machine of value T in that cell (if there is one) will change his vertical speed by T, and the speedo of value Q in that cell (if there is one) will change his vertical speed by Q. For example, if Facer’s vertical speed is v when he arrives at a cell with a speed changing machine of value T and a speedo of value Q, his vertical speed will be changed to v + T + Q immediately. There are three more things you need to know about speed changing:

- All speed changing machines in the surface cells can’t work.
- When reaching a surface cell without a speedo, Facer’s vertical speed becomes zero immediately; and when reaching a surface cell with a speedo of value Q, Facer’s vertical speed becomes Q immediately.
- When reaching a bottom cell, though Facer can’t go down any more, his vertical speed will NOT be changed unless there is a speedo or a speed changing machine in that cell. It’s maybe sound a little bit weird but Facer really is such a weird guy.

When arriving at a cell with a money box of value P, Facer gets P dollars (In fact, if P is negative, Facer loses |P| dollars). Facer’s total amount of money can be negative — that means Facer owes some money to the pool’s owner.

You task is deploying your speedos in a smart way before Facer starts swimming, so Facer can get money as much as possible when he arrives at cell (1, M). Facer’s initial vertical speed is zero and if you put a speedo in the cell (1,1), it will change Facer’s initial vertical speed.

Input

The first line contains three integers N,M and K ( 1 <= N <= 100, 1 <= M <= 1000, 1 <= K <= 10), tells the size of the pool and Facer must refill the oxygen bottle every K seconds.

Following are N lines describing the cells by top to bottom order. Each line contains M elements, separated by blanks, telling the information about the cells of a row, by left to right order. There are only two kinds of elements:

- a char “v” followed by an integer T, meaning that there is a “speed changing machine” of value T (-20 <= T <= 20) in the correspondent cell.
- a char “$” followed by an integer P, meaning that there is a “money box” of value P (-1000000 <= P <= 1000000) in the correspondent cell.

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）：

#include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; typedef long long LL; const int MAXN = 110; const int MAXM = 1010; const int INF = 0x3fff3fff; int dp[MAXM]; int mat[MAXN][MAXM]; bool money[MAXN][MAXM]; int n, m, k; void dfs(int from, int ti, int tj, int spd, int sum) { if(ti < 1) ti = 1; if(ti > n) ti = n; if(ti == 1 && from != tj) { if(dp[tj] < sum) dp[tj] = sum; return ; } if(tj - from == k || tj == m) return ; if(money[ti][tj]) sum += mat[ti][tj]; else if(ti != 1) spd += mat[ti][tj]; dfs(from, ti + spd - 1, tj + 1, spd - 1, sum); dfs(from, ti + spd , tj + 1, spd , sum); dfs(from, ti + spd + 1, tj + 1, spd + 1, sum); } void solve() { dp[1] = 0; for(int i = 2; i <= m; ++i) dp[i] = -INF; for(int i = 1; i < m; ++i) { if(dp[i] == -INF) continue; dfs(i, 1, i, 0, dp[i]); } //for(int i = 1; i <= m; ++i) printf("%d\n", dp[i] + money[1][i] * mat[1][i]); if(money[1][m]) dp[m] += mat[1][m]; printf("%d\n", dp[m]); } char lastch = ' '; inline char readchar() { while(lastch != 'v' && lastch != '$') lastch = getchar(); return lastch; } inline int readint() { int g = 0, l; while(!isdigit(lastch) && lastch != '-') lastch = getchar(); if(lastch == '-') { l = -1; lastch = getchar(); } else l = 1; while(isdigit(lastch)) { g = g * 10 + lastch - '0'; lastch = getchar(); } return g * l; } int main() { while(true) { n = readint(); m = readint(); k = readint(); if(n + m + k == 0) break; char c; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { //scanf(" %c%d", &c, &mat[i][j]); c = readchar(); mat[i][j] = readint(); money[i][j] = (c == '$'); } } solve(); } }

View Code

代码（POJ 1922MS）：

#include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; typedef long long LL; const int MAXN = 110; const int MAXM = 1010; const int INF = 0x3fff3fff; int dp[MAXM]; int mat[MAXN][MAXM]; bool money[MAXN][MAXM]; int n, m, k; void dfs(int from, int ti, int tj, int spd, int sum) { if(ti < 1) ti = 1; if(ti > n) ti = n; if(ti == 1 && from != tj) { if(dp[tj] < sum) dp[tj] = sum; return ; } if(tj - from == k || tj == m) return ; if(money[ti][tj]) sum += mat[ti][tj]; else if(ti != 1) spd += mat[ti][tj]; dfs(from, ti + spd - 1, tj + 1, spd - 1, sum); dfs(from, ti + spd , tj + 1, spd , sum); dfs(from, ti + spd + 1, tj + 1, spd + 1, sum); } void solve() { dp[1] = 0; for(int i = 2; i <= m; ++i) dp[i] = -INF; for(int i = 1; i < m; ++i) { if(dp[i] == -INF) continue; dfs(i, 1, i, 0, dp[i]); } if(money[1][m]) dp[m] += mat[1][m]; printf("%d\n", dp[m]); } int main() { while(scanf("%d%d%d", &n, &m, &k) != EOF) { if(n + m + k == 0) break; char c; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { scanf(" %c%d", &c, &mat[i][j]); money[i][j] = (c == '$'); } } solve(); } }

View Code

参考：http://www.cnblogs.com/oyking/p/3268737.html

沙发呢，我抢到了沙发

其实就是DFS搜索，数据量较小，穷举了所有情况

可以参考算法导论中的时间戳。就是结束访问时间，最后结束的顶点肯定是入度为0的顶点，因为DFS要回溯

A的话不是不能避免冲突么？感觉出题者在考察是否考虑了冲突解决办法？

这道题目的核心一句话是：取还是不取。

如果当前取，则index+1作为参数。如果当前不取，则任用index作为参数。

第一句可以忽略不计了吧。从第二句开始分析，说明这个花色下的所有牌都会在其它里面出现，那么还剩下♠️和♦️。第三句，可以排除2和7，因为在两种花色里有。现在是第四句，因为♠️还剩下多个，只有是♦️B才能知道答案。

不好意思，写错了．应该是 path[0]=0, visited[V] = true;

能不能说一下tmp数组和solve都是干嘛的？

加了星号 (*) 表示跳过此数据不读入. 因为scanf是不读取本行回车的

你好，这题给出的代码好像弄错了，这个是pow那道题目的解法

妈呀！这个Dijkstra模板好长OwQ！