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);
}