棋盘型DP
考虑记录位置
常见题型高维,多路径
T1 传纸条
好题!
CCF出品,必属精品!
考虑转化题意
从起点到终点只能往右或往下
求路径上值之和最大
考虑记录状态
棋盘型DP
考虑记录坐标f[x1][y1][x2][y2]
考虑转移
f[x1][y1][x2][y2]=max(f[x1][y1-1][x2][y2-1],f[x1][y1-1][x2-1][y2],f[x1-1][y1][x2][y2-1],f[x1-1][y1][x2-1][y2])+a[x1][y1]+a[x2][y2]
即四种走下来的方法取max
考虑保证路径不重合
发现步数一致(当然是一致的)
考虑曼哈顿距离
显然每个状态都在一个棋盘的上三角形(还是等腰的)的斜边边界上
显然要选两个点
而且下面一个点确定了上面的点就只能在斜边边界上往上找了
考虑优化
上面已经提到两个点的相对位置
考虑枚举下面的点,利用这个相对位置算出上面的点
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=100;
int a[N][N],n,m,f[N][N][N];
int main(){
n=in,m=in;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=in;
for(int step=3;step<=n+m;++step)
for(int x1=1,y1=step-x1;x1<=n;++x1,--y1){
if(y1>m) continue;
for(int x2=x1+1,y2=step-x2;x2<=n;++x2,--y2){
if(y2>m) continue;
f[step][x1][x2]=max(max(f[step-1][x1][x2],f[step-1][x1-1][x2-1]),max(f[step-1][x1-1][x2],f[step-1][x1][x2-1]));
f[step][x1][x2]+=a[x1][y1]+a[x2][y2];
}
}
printf("%d\n",f[n+m-1][n-1][n]);
// for(int k=1;k<=m+n;++k)
// for(int i=1;i<=n;++i)
// for(int j=1;j<=n;++j)
// printf("%d(%d,%d,%d) ",f[k][i][j],k,i,j);
return 0;
}
hurray!基本上是自己做出来的
T2 方格取数
棋盘型DP
和传纸条一样,发现每一步都有一个层次:
上三角形的斜边,只有斜边
没有前效性,DP妥妥的
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int N=50;
int a[N][N],n,m,f[N][N][N];
int main(){
n=in;
int x,y,w;
while(x=in){
y=in,w=in;
a[x][y]=w;
}
for(int step=2;step<=n+n;++step){
for(int x1=1,y1=step-x1;x1<=n&&y1>=1;++x1,--y1){
for (int x2=1, y2=step-x2;x2<=n&&y2>=1;++x2, --y2) {
f[step][x1][x2]=max(max(f[step-1][x1][x2], f[step-1][x1-1][x2-1]), max(f[step-1][x1-1][x2], f[step-1][x1][x2-1]));
f[step][x1][x2]+=(x1==x2&&y1==y2)?a[x1][y1]:(a[x1][y1]+a[x2][y2]);
}
}
}
printf("%d\n",f[n+n][n][n]);
// for(int k=1;k<=m+n;++k)
// for(int i=1;i<=n;++i)
// for(int j=1;j<=n;++j)
// printf("%d(%d,%d,%d) ",f[k][i][j],k,i,j);
return 0;
}