E02 线性DP P1216 数字三角形

E02 线性DP 数字三角形_哔哩哔哩_bilibili

 

P1216 [IOI 1994 / USACO1.5] 数字三角形 Number Triangles - 洛谷

// 线性DP O(n^2)
#include<bits/stdc++.h>
using namespace std;

const int N=1005;
int n,a[N][N],f[N][N]; //f[i,j]表示以 (i,j) 为顶点的子三角形,路径和的最大值

int main(){
  scanf("%d",&n);
  for(int i=1; i<=n; i++)
    for(int j=1; j<=i; j++) scanf("%d",&a[i][j]);
    
  for(int i=n; i>=1; i--)
    for(int j=1; j<=i; j++)
      f[i][j]=max(f[i+1][j],f[i+1][j+1])+a[i][j];
    
  printf("%d\n",f[1][1]);
}

 

P1004 [NOIP 2000 提高组] 方格取数 - 洛谷

等价于两人同时走,并且走相同步数。条件:i+j == x+y
f[i,j,x,y]表示两人从 (1,1) 同步走到 (i,j)、(x,y) 的路径和的最大值

// 线性DP O(n^4)
#include<iostream>
using namespace std;

const int N=11;
int n,x,y,a[N][N];
int f[N][N][N][N]; //f[i,j,x,y]表示两人从 (1,1) 同步走到 (i,j)、(x,y) 的路径和的最大值

int main(){
  cin>>n;  
  while(cin>>x>>y>>a[x][y],x);
  
  for(int i=1; i<=n; i++)
  for(int j=1; j<=n; j++)
  for(int x=1; x<=n; x++)
  for(int y=1; y<=n; y++)
    if(i+j==x+y){
      f[i][j][x][y]=max(max(f[i-1][j][x-1][y],f[i-1][j][x][y-1]),
                        max(f[i][j-1][x-1][y],f[i][j-1][x][y-1]))+a[i][j]+a[x][y];
      if(i==x && j==y) f[i][j][x][y]-=a[i][j]; //同一点去重
    }
    
  cout<<f[n][n][n][n];
}

利用约束条件,降维优化,令 i+j=x+y=k 表示走的步数
f[k,i,x]表示共走了k步,两人分别走到i行x行,取数的最大值

// 线性DP O(n^3)
#include<bits/stdc++.h>
using namespace std;

const int N=11;
int n,x,y,a[N][N],f[N+N][N][N];

int main(){
  cin>>n;
  while(cin>>x>>y>>a[x][y],x);
  
  for(int k=2; k<=n+n; k++) //走了k步
  for(int i=1; i<=n; i++)   //走到i行
  for(int x=1; x<=n; x++){  //走到x行
    int j=k-i,y=k-x;
    if(j>=1&&j<=n&&y>=1&&y<=n){
      f[k][i][x]=max(max(f[k-1][i-1][x-1],f[k-1][i-1][x]),
                     max(f[k-1][i][x-1],f[k-1][i][x]))+a[i][j]+a[x][y];
      if(i==x) f[k][i][x]-=a[i][j];
    }
  }
  cout<<f[n+n][n][n];
}

 

P1006 [NOIP 2008 提高组] 传纸条 - 洛谷

// 线性DP O(n^3)
#include<bits/stdc++.h>
using namespace std;

const int N=55;
int m,n,a[N][N];
int f[N+N][N][N];

int main(){
  cin>>m>>n;
  for(int i=1; i<=m; i++)
  for(int j=1; j<=n; j++) cin>>a[i][j];
  
  for(int k=2; k<=m+n; k++) //步数
  for(int i=1; i<=m; i++)   //
  for(int x=1; x<=m; x++){  //
    int j=k-i, y=k-x;
    if(j<1 || j>n || y<1 || y>n) continue;
    f[k][i][x]=max(max(f[k-1][i-1][x-1],f[k-1][i-1][x]), 
                   max(f[k-1][i][x-1], f[k-1][i][x]))+a[i][j]+a[x][y];
    if(i==x) f[k][i][x]-=a[i][j];
  }
  cout<<f[m+n][m][m];
}
 

 

posted @ 2023-04-09 18:45  董晓  阅读(870)  评论(0)    收藏  举报