akoj-1369 貪喫蛇

貪喫蛇

Time Limit:1000MS Memory Limit:65536K
Total Submit:9 Accepted:2

Description

有童年的孩子都玩過這個經典遊戲,不過這裏的規則又有點不同,現在有一個N*M(N,M<=100)的方形矩形,在這個矩形的每一個方格上都放有若干個櫻桃,一條可愛的小蛇從矩形的
左上角開始出發,每次移動都只能移動一格,向右或向下,而每到達一格貪喫的小蛇都會吧該位置上的櫻桃喫個一乾二淨,直到到達右下角時停止。而貪喫的小蛇不怕撐死,它只想喫到最多
的櫻桃,請你告訴它他最多能喫到多少櫻桃以及具體路線吧。(數據保證最優路線只有一條)

Input

每個輸入包含多個測試用例,每個測試用例第一行給出N,M,接下來N行M列數據代表每個位置上的櫻桃個數。(矩陣座標從(1,1)開始)。

Output

對於每個測試用例輸出第一行爲能喫到的最大櫻桃個數,接下來爲小蛇所需要走的路線的座標,每個座標佔一行。

Sample Input

4 4 
1 2 3 7
3 4 2 1
1 5 4 8
10 3 0 3

Sample Output

28
(1,1)
(2,1)
(2,2)
(3,2)
(3,3)
(3,4)
(4,4)

Source

icpc7th@ahstu

思路:

這一題需要用到動態規劃,由於貪喫蛇每次只能往右或往下走,所以對於每一個格子而言,當前格子的最大值(dp[i][j]) =  當前格子的值(a[i][j]) + max{當前格子上方格子的最大值dp[i-1][j],  當前格子左方格子的最大值dp[i][j-1]}。

即 表達式爲dp[i][j] = a[i][j] + max(dp[i-1][j], dp[i][j-1])

好了,最大值即爲dp[n][m], 求出了最大值,就需要求路徑了,因爲我們之前把每個格子的最大值都求出來了,所以從右下角開始倒推即可,首先將最後一個格子的座標保存起來,我是放在在了stack中,然後依次放入當前上方的格子或左邊的格子的座標,因爲當前格子的最大值是上方或左方格子的最大值+當前格子最初的值得來的,所以只需保存上方和左方格子中較大一個格子的座標

需要注意的是當到了邊界時,在左邊界,只可以往上走了,所以需要把格子上方的座標都保存起來,同理上方也一樣,下面給出,c++和Java版的代碼

歡迎大家提出寶貴意見

c++

#include <iostream>
#include <cstdio>
#include <stack>

using namespace std;

stack<int> st;
int a[101][101], dp[101][101], n, m;

void scan()
{
    for (int i=1; i<=n; i++)
        for (int j=1; j<=m; j++)
            scanf("%d", &a[i][j]);
    for (int i=0; i<=n; i++)
        dp[i][0] = 0;
    for (int j=0; j<=m; j++)
        dp[0][j] = 0;
}

int solve()
{
    for (int i=1; i<=n; i++)
        for (int j=1; j<=m; j++)
            dp[i][j] = a[i][j] + max(dp[i-1][j], dp[i][j-1]);
    return dp[n][m];
}

void Pu(int n, int m)
{
    st.push(m);
    st.push(n);
    if (n == 1 && m == 1)
        return;
    else if (n == 1 && m > 1)
        Pu(n, m-1);
    else if (n > 1 && m == 1)
        Pu(n-1, m);
    else {
        if (dp[n-1][m] > dp[n][m-1])
            Pu(n-1, m);
        else
            Pu(n, m-1);
    }
}

void printPath()
{
    Pu(n, m);
    while (!st.empty()){
        printf("(%d,", st.top());
        st.pop();
        printf("%d)\n", st.top());
        st.pop();
    }
}

int main()
{
    while (~scanf("%d%d", &n, &m)){
        scan();
        printf("%d\n", solve());
        printPath();
    }
    return 0;
}

java

import java.util.Scanner;
import java.util.Stack;

public class P1369 {
    static int n, m, a[][], dp[][];
    static Stack<Integer> stack;
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        while (cin.hasNext()) {
            n = cin.nextInt();
            m = cin.nextInt();
            a = new int[n+1][m+1];
            dp = new int[n+1][m+1];
            for (int i=1; i<=n; i++) {
                for (int j=1; j<=m; j++)
                    a[i][j] = cin.nextInt();
            }
            System.out.println(solve());
            printPath();
        }
        cin.close();
    }
    private static void printPath() {
        stack = new Stack<>();
        Pu(n, m);
        while (!stack.isEmpty()) {
            System.out.println("("+stack.pop()+","+stack.pop()+")");
        }
        stack.removeAllElements();
    }
    private static void Pu(int n, int m) {
        stack.push(m);
        stack.push(n);
        if (n == 1 && m == 1)
            return;
        else if (n == 1 && m > 1)
            Pu(n, m-1);
        else if (n > 1 && m == 1)
            Pu(n-1, m);
        else {
            if (dp[n-1][m] > dp[n][m-1])
                Pu(n-1, m);
            else 
                Pu(n, m-1);
        }
    }
    private static int solve() {
        for (int i=0; i<=n; i++)
            dp[i][0] = 0;
        for (int j=0; j<=m; j++)
            dp[0][j] = 0;
        for (int i=1; i<=n; i++) {
            for (int j=1; j<=m; j++) {
                dp[i][j] = a[i][j] + Math.max(dp[i-1][j], dp[i][j-1]);
            }
        }
        return dp[n][m];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章