Блог пользователя aajjbb

Автор aajjbb, 14 лет назад, По-английски

Hi, I'm strugglin with the follow problem; Given a N * M rectangle with nums between -500 — 500, return the values of the longest sum of cells from cell (0, 0) to cell (N-1, M-1), you can make the moves (i + 1, j), (i, j + 1) and (i, j — 1), you can only visit a cell one time.

I tried the DP strategy:

//dp[i][j] is the longest sum path until the cell (i, j)
//maze[i][j] value in the cell (i, j)
dp[i][j] = max(maze[i][j], max(dp[i - 1][j] + maze[i][j], max(dp[i][j - 1] + maze[i][j], dp[i][j + 1] + maze[i][j])));

this strategy isn't working due to the test case:

81 28 240 10
40 10 100 240
20 180 110 35

the answer is: 1094 this strategy returns: 724.

what is the optimal strategy ? Thanks.

  • Проголосовать: нравится
  • 0
  • Проголосовать: не нравится

»
14 лет назад, скрыть # |
← Rev. 2  
Проголосовать: нравится +8 Проголосовать: не нравится

An obviously cubic solution:

dp[0][0] = maze[0][0];
for (int i = 0; i < n - 1; i++) {
	for (int j = 0; j < m; j++) {
		if (i == 0 && j != 0) {
			continue;
		}
		int leftsum = 0;
		for (int k = j - 1; k >= 0; k--) {
			leftsum += maze[i][k];
			dp[i + 1][k] = max(dp[i + 1][k], dp[i][j] + leftsum + maze[i + 1][k]);
		}
		int rightsum = 0;
		for (int k = j + 1; k < m; k++) {
			rightsum += maze[i][k];
			dp[i + 1][k] = max(dp[i + 1][k], dp[i][j] + rightsum + maze[i + 1][k]);
		}
	}
}

The answer will be in dp[n - 1][m - 1].

»
14 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Your strategy is solving problem with different set of moves.

»
14 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

It's problem from Timus Online Judge again :) Timus is offline now, so this is Google cache link: 1029 — Ministry.
One difference is that you should find the minimal path, not maximal.

  • »
    »
    14 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    Minimal path can be solved with more optimal (and obvious :) dijkstra in n2logn.

    • »
      »
      »
      14 лет назад, скрыть # ^ |
       
      Проголосовать: нравится 0 Проголосовать: не нравится

      Yes, I've started with the Dijsktra idea, but it doesn't work for 'Longest-Paths', so I moved to the dp solution, which isn't working till now..

      • »
        »
        »
        »
        14 лет назад, скрыть # ^ |
         
        Проголосовать: нравится +8 Проголосовать: не нравится

        It still can be solved in O(n*m) using graphs.
        Let's split each cell into three vertices:
        0 if we came using i+1 and can move in any allowed direction;
        1 if we came using j-1 and unable to move back(increasing j);
        2 if we came using j+1 and unable to move back(decreasing j).

        So there would be such edges(of course if they do not go out of the field):

        [i][j][0] -> [i+1][j][0]  
        [i][j][0] -> [i][j-1][1]  
        [i][j][0] -> [i][j+1][2]  
        [i][j][1] -> [i+1][j][0]  
        [i][j][1] -> [i][j-1][1]  
        [i][j][2] -> [i+1][j][0]  
        [i][j][2] -> [i][j+1][2]  
        

        such graph is acyclic so simple DFS/BFS will solve problem.

»
14 лет назад, скрыть # |
← Rev. 7  
Проголосовать: нравится +8 Проголосовать: не нравится

We can solve it in O(n*m) time. We can use DP with 3 parameters — current row, current column, and another parameter, which describes the direction we used to get on our current cell.

UPD: Oh, there was a silly bug in previous implementation (I forgot that the matrix can contain negative numbers). So, I believe that the right code is in Rev.5

»
14 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

I hope it is true solution:

for(i = 1; i <= m; i++)
    dp[1][i] = sum[1][i];

for(i = 2; i <= n; i++){
    for(j = 1; j <= m; j++){
        dp[i][j] = -INF;
        for(k = 1; k <= m; k++){
            if(k<=j)
                dp[i][j] = max(dp[i][j], dp[i-1][k] + sum[i][j] - sum[i][k-1]);
            else
                dp[i][j] = max(dp[i][j], dp[i-1][k] + sum[i][k] - sum[i][j-1]);
        }
    }
}

where sum[i][j] is sum of i'th row from 1 to j inclusive and dp[i][j] is the values of the longest sum of cells from cell (1, 1) to cell (i, j).

Answer will be in dp[n][m].

»
14 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

I think I have a linear time solution for this one, i'll post it soon.

  • »
    »
    14 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    There you go, give it a spin:

    memset(Dp,128,sizeof(Dp)); //sets everything to -INF
        Dp[1][1] = A[1][1];
        for (i=2; i<=N+1; i++){
            //solving the i-th row will take 2 passes:
            memset(Left,128,sizeof(Left)); 
            memset(Right,128,sizeof(Right));
            Left[1] = Dp[i-1][1] + A[i][1];
            for (j=2; j<=M; j++) Left[j] = A[i][j] + max(Left[j-1] - A[i][j-1] + A[i-1][j] , Dp[i-1][j]);
            Right[M] = Dp[i-1][M] + A[i][M];
            for (j=M-1; j; j--) Right[j] = A[i][j] + max(Right[j+1] - A[i][j+1] + A[i-1][j] , Dp[i-1][j]);
            for (j=1; j<=M; j++) Dp[i][j] = max(Left[j],Right[j]);
        }
    

    The solution can be found in Dp[N+1][M] I used the (1,1)..(N,M) convention. Dp[i][j] stores the maximum value of a valid path from (1,1)..(i,j) which enters the field (i,j) from above, that is, from (i-1,j).

    Full implementation: Here