1. 程式人生 > >hdoj 5092 Seam Carving 【樹塔DP變形 + 路徑輸出】 【簡單題】

hdoj 5092 Seam Carving 【樹塔DP變形 + 路徑輸出】 【簡單題】

mes class mar constant it is tor char 題意 esp

Seam Carving

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 956 Accepted Submission(s): 382

Problem Description Fish likes to take photo with his friends. Several days ago, he found that some pictures of him were damaged. The trouble is that there are some seams across the pictures. So he tried to repair these pictures. He scanned these pictures and stored them in his computer. He knew it is an effective way to carve the seams of the images He only knew that there is optical energy in every pixel. He learns the following principle of seam carving. Here seam carving refers to delete through horizontal or vertical line of pixels across the whole image to achieve image scaling effect. In order to maintain the characteristics of the image pixels to delete the importance of the image lines must be weakest. The importance of the pixel lines is determined in accordance with the type of scene images of different energy content. That is, the place with the more energy and the richer texture of the image should be retained. So the horizontal and vertical lines having the lowest energy are the object of inspection. By constantly deleting the low-energy line it can repair the image as the original scene.

技術分享

For an original image G of m*n, where m and n are the row and column of the image respectively. Fish obtained the corresponding energy matrix A. He knew every time a seam with the lowest energy should be carved. That is, the line with the lowest sum of energy passing through the pixels along the line, which is a 8-connected path vertically or horizontally.

Here your task is to carve a pixel from the first row to the final row along the seam. We call such seam a vertical seam.
Input There several test cases. The first line of the input is an integer T, which is the number of test cases, 0<T<=30. Each case begins with two integers m, n, which are the row and column of the energy matrix of an image, (0<m,n<=100). Then on the next m line, there n integers.
Output For each test case, print “Case #” on the first line, where # is the order number of the test case (starting with 1). Then print the column numbers of the energy matrix from the top to the bottom on the second line. If there are more than one such seams, just print the column number of the rightmost seam.
Sample Input
2
4 3
55 32 75
17 69 73
54 81 63
47 5 45
6 6
51 57 49 65 50 74
33 16 62 68 48 61
2 49 76 33 32 78
23 68 62 37 69 39
68 59 77 77 96 59
31 88 63 79 32 34

Sample Output
Case 1
2 1 1 2
Case 2
3 2 1 1 2 1

題意:給一個N*M的矩陣,讓你用一條線 從第1行連到第N行(每行僅僅能選一個元素),要求這條線所經過的元素之和最小。 有下面規定—— 1,若你選擇了位置(i,j)的元素,那麽下一行的元素你僅僅能選擇(i+1。j-1)、(i+1。j)、(i+1,j+1)三個之中的一個(當然邊界僅僅能選兩個)。

2,若能夠找到多條 路徑上元素之和最小 的線,那麽你要優先選擇最右邊的線。 3。最後從第一行開始 輸出線上元素的縱坐標。



思路:就是樹塔變形題嘛。在自底往上推最優值的過程中。設置數組記錄前驅,最後選擇最右邊的線輸出路徑就可以。因為題目沒有說清楚(可能是我英語太渣)在找線的過程中是否要優先選擇最右邊的元素,所以我在DP過程中選擇從左到右一直更新前驅。



隊友說DP難,沒心情深挖。

沒辦法,僅僅好主修圖論 + DP。 其他僅僅能輔修了o(╯□╰)o
AC代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Node
{
    int pos;
};
Node mark[110][110];//標記該位置是由 哪一位置得到的(自底往上)
int dp[110][110];
int N, M;
int k = 1;
void getMap()
{
    for(int i = 1; i <= N; i++)
    {
        for(int j = 1; j <= M; j++)
            scanf("%d", &dp[i][j]);
    }
}
void solve()
{
    int t;
    for(int i = N-1; i >= 1; i--)
    {
        for(int j = 1; j <= M; j++)
        {
            if(j == 1)
            {
                t = min(dp[i+1][j], dp[i+1][j+1]);//找到最小值
                dp[i][j] += t;
                //從左到右更新 前驅
                if(t == dp[i+1][j])
                    mark[i][j].pos = j;
                if(t == dp[i+1][j+1])
                    mark[i][j].pos = j + 1;
            }
            else if(j == M)
            {
                t = min(dp[i+1][j], dp[i+1][j-1]);
                dp[i][j] += t;
                if(t == dp[i+1][j-1])
                    mark[i][j].pos = j - 1;
                if(t == dp[i+1][j])
                    mark[i][j].pos = j;
            }
            else
            {
                int t = min(dp[i+1][j], min(dp[i+1][j-1], dp[i+1][j+1]));
                dp[i][j] += t;
                if(t == dp[i+1][j-1])
                    mark[i][j].pos = j-1;
                if(t == dp[i+1][j])
                    mark[i][j].pos= j;
                if(t == dp[i+1][j+1])
                    mark[i][j].pos = j+1;
            }
        }
    }
    int sx = 1;
    int Max = dp[1][1];
    for(int i = 2; i <= M; i++)
    {
        if(Max >= dp[1][i])//優先選擇最右邊的線
        {
            Max = dp[1][i];
            sx = i;
        }
    }
    printf("Case %d\n", k++);
    printf("%d", sx);
    int row = 1, cul = sx;//行號 列號
    while(1)
    {
        if(row == N) break;
        cul = mark[row][cul].pos;//下一列號
        printf(" %d", cul);
        row++;
    }
    printf("\n");
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &N, &M);
        getMap();
        solve();
    }
    return 0;
}


hdoj 5092 Seam Carving 【樹塔DP變形 + 路徑輸出】 【簡單題】