最初のトピック
タイトルの説明:
N×Nグリッドがあります。いくつかの正方形には正の整数を入力し、他の正方形には数値0を入力します。以下に示すように:
誰かが図の左上隅のAから始まり、右下隅のポイントBに到達するまで下または右に歩くことができます。
彼が歩いている途中で、彼は正方形の中で数をとることができます(それを取った後の正方形は数0になります)。
この人物は、ポイントAからポイントBまで2回歩いています。取得した数値の合計が最大になるように、このような経路を2つ見つけてみてください。
入力フォーマット
1行目は整数Nで、N×Nグリッドグラフを表します。
次の各行には3つの整数があり、最初の行は行番号、2番目は列番号、3番目は行と列に配置された番号です。
行と列の番号は1から始まり、行 "0 0 0"は終わりを意味します。
出力フォーマット
2つのパスで取得された最大の合計を表す整数を出力します。
データ範囲
N≤10
入力サンプル:
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
出力例:
67
アイデア
一般的な方法 4次元dp
这个题要求的是走两遍,每次的最大值相加,选过的
方格值为0,一开始我想的是两次二维dp,选过的直接
为0,试验之后发现第二次的dp值为0,才想起来第一
此dp把所有的每格子可能的最大值全算出来了,也就是
说所有的格子都用过。
于是网上看到的常见的是四维dp,大概思路是这样
1.想象两个人在这个方格中走,每个人有一条路径,
总的就是两条路径,dp[i][j][k][l]表示第一个人
走到(i,j)这个格子的时候第二个走到(k,l)这
个格子的时候的最大值,答案就是dp[N][N][N][N],
正好表示第一个人走到(N,N)第二个人也走到了(N,N)
正好是两条路径;
2. 当两个人走到同一个格子的时候,格子的值只能加
一次,还有就是第一个人走到(i,j)有两种方法:要
么从上往下走走到了,要门从左往右走走到了,这样两
个人就有了“四种”状态,取这四种状态的最大值,就是
最后的答案;
コード
public class Main{
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int N=input.nextInt();
int [][]arr=new int[N+2][N+2];
for(int i=1;i<=12;i++){
int x=input.nextInt();
int y=input.nextInt();
arr[x][y]=input.nextInt();
}
int [][][][]dp=new int [N+1][N+1][N+1][N+1];
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
for(int k=1;k<=N;k++){
for(int l=1;l<=N;l++){
//第一个和第二个都是从下往上来
//第一个从上往下第二个从左往右
int temp1=Math.max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]);
//第一个左往右第二个从上往下
//第一个和第二个都是从左往右
int temp2=Math.max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]);
dp[i][j][k][l]=Math.max(temp1,temp2)+arr[i][j];
//坐标不相等时加两次
if(i!=k&&j!=l) dp[i][j][k][l]+=arr[k][l];
}
}
}
}
System.out.println(dp[N][N][N][N]);
}
}
ヤンのDP分析
メソッドyは常に4次元DPを3次元DPに変換します。私たちが探しているのは2回歩くことであり、2人が同時に歩くと見なすことができ、同じグリッドを繰り返し選択することができないため、同時に歩いて別々に歩くことの最終結果は同じ。
2つのルートを同時に使用すると、それらの横座標と縦座標の合計は同じです。この合計をKに設定します因此(i,j)就可以表示为(i,K-i)
。dp[K] [i1] [i2]は表示两个人从(1,1)分别走到(i1,K-i1)和(i2,K-i2)所有路径的最大值
理解しにくいので、2つの画像に移動します
次に、コード:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int N=input.nextInt();
int [][]arr=new int[N+2][N+2];
for(int i=1;i<=12;i++){
int x=input.nextInt();
int y=input.nextInt();
int z=input.nextInt();
if(x==0&&y==0&&x==0)
{
break;
}
else arr[x][y]=z;
}
//K表示横纵坐标之和走两条路,同时走所以x+y的值是一定的
//当i1==i2, 两个在同一格,就只需要加一次
int dp[][][]=new int [N*2+2][N+1][N+1];
for(int k=2;k<=N+N;k++){
for(int i1=1;i1<=N;i1++){
for(int i2=1;i2<=N;i2++){
int j1=k-i1;
int j2=k-i2;
//看是否符合要求
if(j1>=1&&j1<=N&&j2>=1&&j2<=N){
int t=arr[i1][j1];
if(i1!=i2)t+=arr[i2][j2];
int temp=dp[k][i1][i2];
temp=Math.max(temp,dp[k-1][i1-1][i2-1]+t);//上上
temp=Math.max(temp,dp[k-1][i1-1][i2]+t); //下右、
temp=Math.max(temp,dp[k-1][i1][i2-1]+t); //右下
temp=Math.max(temp,dp[k-1][i1][i2]+t); //右右
dp[k][i1][i2]=temp;
}
}
}
}
System.out.println(dp[N+N][N][N]);
}
}