貪喫蛇
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
思路:
這一題需要用到動態規劃,由於貪喫蛇每次只能往右或往下走,所以對於每一個格子而言,當前格子的最大值(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];
}
}