数字三角形模型
P1015 摘花生
闫氏DP分析法:从集合角度思考
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int f[N][N];
int w[N][N];
int n,m;
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&w[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=max(f[i-1][j],f[i][j-1])+w[i][j];
}
}
printf("%d\n",f[n][m]);
}
return 0;
}
P1018 最低通行费
由题目已知条件可以推出不能走回头路,不然时间会超,由此转变成“摘花生”题目
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110,INF=1e9;
int f[N][N];
int w[N][N];
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&w[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==1&&j==1) f[i][j]=w[i][j];
else{
f[i][j]=INF;
//下面要特判,否则答案会错误
if(i>1) f[i][j]=min(f[i][j],f[i-1][j]+w[i][j]);//不是第一行才可以从上面过来
if(j>1) f[i][j]=min(f[i][j],f[i][j-1]+w[i][j]);//不是第一列才可以从左边过来
}
}
}
printf("%d\n",f[n][n]);
return 0;
}
P1027 方格取数
思路:两条路径同时走
为什么不能分开走(贪心): 第一次走为局部最优并且也对第二次走造成了影响,第二次走是在第一次最优的情况下所能走的局部最优,不具备“无后效性”,并不是全局最优解
注意两个格子重合时满足i1+j1=i2+j2,满足i1+j1=i2+j2不一定重合
#include<iostream>
#include<algorithm>
using namespace std;
const int N=15;
int f[N*2][N][N];
int w[N][N];
int n;
int main(){
scanf("%d",&n);
int a,b,c;
while(scanf("%d%d%d",&a,&b,&c),a||b||c) w[a][b]=c;
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,j2=k-i2;
if(j1>=1&&j1<=n&&j2>=1&&j2<=n){
int t=w[i1][j1];
if(i1!=i2) t+=w[i2][j2];//不重合时两个都要加
f[k][i1][i2]=max(f[k][i1][i2],f[k-1][i1-1][i2-1]+t);
f[k][i1][i2]=max(f[k][i1][i2],f[k-1][i1-1][i2]+t);
f[k][i1][i2]=max(f[k][i1][i2],f[k-1][i1][i2-1]+t);
f[k][i1][i2]=max(f[k][i1][i2],f[k-1][i1][i2]+t);
}
}
}
}
printf("%d\n",f[n+n][n][n]);
return 0;
}
P275 传纸条
和方格取数一毛一样,只不过推广到了长方形
#include<iostream>
#include<algorithm>
using namespace std;
const int N=55;
int f[N*2][N][N];
int w[N][N];
int n,m;
int main(){
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
scanf("%d",&w[i][j]);
}
}
for(int k=2;k<=n+m;k++){
for(int i1=1;i1<=m;i1++){
for(int i2=1;i2<=m;i2++){
int j1=k-i1,j2=k-i2;
if(j1>=1&&j1<=n&&j2>=1&&j2<=n){
int t=w[i1][j1];
if(i1!=i2) t+=w[i2][j2];//不重合时两个都要加
f[k][i1][i2]=max(f[k][i1][i2],f[k-1][i1-1][i2-1]+t);
f[k][i1][i2]=max(f[k][i1][i2],f[k-1][i1-1][i2]+t);
f[k][i1][i2]=max(f[k][i1][i2],f[k-1][i1][i2-1]+t);
f[k][i1][i2]=max(f[k][i1][i2],f[k-1][i1][i2]+t);
}
}
}
}
printf("%d\n",f[n+m][m][m]);
return 0;
}