DP问题之数字三角形模型

数字三角形模型

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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值