zoukankan      html  css  js  c++  java
  • HDU 5092 Seam Carving

    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的矩阵,从第一行走到最后一行,可以走三个方向,左下 正下 右下,使得这个路径权值最短。如果有权值一样的路径,优先输出靠右的路径。 
    这个和最简单的数字三角形类似,这是个数字矩形。简单的DP,从上往下更新。不过这个需要记录路径。

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    const int MAXN=110;
    const int INF=0x3f3f3f3f;
    
    int T;
    int m,n;
    int dp[MAXN][MAXN];
    int num[MAXN][MAXN];
    int ans[MAXN][MAXN];
    int anss[MAXN];
    
    void make(int m,int pos)
    {
        //从最右侧开始向左找,逆序存入数组(先存ppath[width],最后存ppath[0]),直到找到起点是0的地方(开始点)
        if (ans[m][pos]==0)
        {
            anss[m]=pos;
            return;
        }
        else
        {
            anss[m]=pos;
            make(m-1,ans[m][pos]);
        }
    }
    
    void DP()
    {
        for(int j=1; j<=n; j++)
            dp[1][j]=num[1][j];
        for(int i=2; i<=m; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if (j!=1 && dp[i-1][j-1]+num[i][j]<dp[i][j])//如果不是第上面一行,并且左上方点权值更小,选择左上方的点
                {
                    dp[i][j]=dp[i-1][j-1]+num[i][j];
                    ans[i][j]=j-1;
                }
                if (dp[i-1][j]+num[i][j]<=dp[i][j])//正左侧点权值更小,选择正左侧的点
                {
                    dp[i][j]=dp[i-1][j]+num[i][j];
                    ans[i][j]=j;
                }
                if (j!=m && dp[i-1][j+1]+num[i][j]<=dp[i][j])//如果不是最下面一行的点并且左下方点权值更小,选择右下方的点
                {
                    dp[i][j]=dp[i-1][j+1]+num[i][j];
                    ans[i][j]=j+1;
                }
            }
        }
        int minn=INF,pos=-1;
        for(int j=n; j>=1; j--)
        {
            if (minn>dp[m][j])
            {
                minn=dp[m][j];
                pos=j;
            }
        }
        make(m,pos);
    }
    
    int main()
    {
        scanf("%d",&T);
        for(int t=1; t<=T; t++)
        {
            memset(ans,0,sizeof(ans));
            memset(anss,0,sizeof(anss));
            for(int i=0; i<MAXN; i++)
                for(int j=0; j<MAXN; j++)
                    dp[i][j]=INF;
            scanf("%d%d",&m,&n);
            for(int i=1; i<=m; i++)
                for(int j=1; j<=n; j++)
                    scanf("%d",&num[i][j]);
            printf("Case %d
    ",t);
            DP();
            for(int i=1; i<m; i++)
                printf("%d ",anss[i]);
            printf("%d
    ",anss[m]);
        }
        return 0;
    }
  • 相关阅读:
    LeetCode 24. Swap Nodes in Pairs (两两交换链表中的节点)
    LeetCode 1041. Robot Bounded In Circle (困于环中的机器人)
    LeetCode 1037. Valid Boomerang (有效的回旋镖)
    LeetCode 1108. Defanging an IP Address (IP 地址无效化)
    LeetCode 704. Binary Search (二分查找)
    LeetCode 744. Find Smallest Letter Greater Than Target (寻找比目标字母大的最小字母)
    LeetCode 852. Peak Index in a Mountain Array (山脉数组的峰顶索引)
    LeetCode 817. Linked List Components (链表组件)
    LeetCode 1019. Next Greater Node In Linked List (链表中的下一个更大节点)
    29. Divide Two Integers
  • 原文地址:https://www.cnblogs.com/aiguona/p/9371509.html
Copyright © 2011-2022 走看看