1.題目
機器人Rob 從方形區域F 的左上角A點出發,向下或向右行走,直到右下角的B 點,在走過的路上,收集方格中的樣本。Rob 從A點到B 點共走2次,試找出Rob 的2條行走路徑,使其取得的樣本總價值最大。
Input:
第1 行有1 個正整數n,表示方形區域F有n*n 個方格。接下來每行有3 個整數,前2 個表示方格位置,第3個數爲該位置樣本價值。最後一行是3個0。
Output:
將計算的最大樣本總價值輸出。
Sample Input
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
Sample Output
67
2.思路
由於機器人只能向下走或向右走 ,故機器人到座標(i,j)時所採集到的樣本價值只依賴於機器人上一步的選擇,即依賴於到(i-1,j)或者(i,j-1)時採集的樣本總價值。
綜上所述,此題我採用動態規劃的方法解題。
1)子問題劃分
設m[i,j]爲機器人從座標(1,1)出發到座標(i,j)停下時所採集到的樣本總價值
2)遞推方程
初值:m[1,i] = m[1,i]+field[1,i]
//i=1,2,...,n field是記錄方形區域F中樣本位置與價值的二維矩陣
m[i,1] = m[i,1]+field[i,1]
遞推式:m[i,j] = max{m[i-1,j] , m[i,j-1]} + field[i,j]
【注】此題由於要採集兩次,故要調用兩次動歸方法,在第一次調用前還應該設計好一個二維數組記錄樣本採集的最大價值的路徑,而在第一次調用完畢後根據記錄的路徑去將該路徑上的樣本價值標爲0
3.代碼
static int n,
field[][];
static String s[][];
static int collectSample(){
int[][] m = new int[n+1][n+1];
//初始化
for(int i=1;i<=n;i++){
m[1][i] += field[1][i];
m[i][1] += field[i][1];
s[1][i] = 1 + "," + (i-1);
s[i][1] = (i-1) + "," + 1;
}
s[1][1] = "0,0";
for(int i=2;i<=n;i++){
for(int j=2;j<=n;j++){
if(m[i-1][j] > m[i][j-1]){
m[i][j] = m[i-1][j] + field[i][j];
s[i][j] = (i-1) + "," + j;
}else{
m[i][j] = m[i][j-1] + field[i][j];
s[i][j] = i + "," + (j-1);
}
}
}
return m[n][n];
}
static void trace(int i,int j){
String xy[] = s[i][j].split(",");
int x = Integer.parseInt(xy[0]);
int y = Integer.parseInt(xy[1]);
field[x][y] = 0; //除去曾採集過的樣本
if(x==0 && y==0)
return ;
trace(x,y);
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
field = new int[n+1][n+1];
s = new String[n+1][n+1];
String temp;
String sample[];
while(!(temp=br.readLine()).equals("0")){//輸入單個數0表示結束輸入
sample = temp.split(" ");
int x = Integer.parseInt(sample[0]);
int y = Integer.parseInt(sample[1]);
int value = Integer.parseInt(sample[2]);
field[x][y] = value;
}
int first = collectSample();
trace(n,n);//執行標記函數,除去採集過的樣本
s = new String[n+1][n+1]; //S重新初始化
int second = first + collectSample();
System.out.println(second);
}