首页 > 其他分享 >坐标dp

坐标dp

时间:2024-02-17 22:23:13浏览次数:20  
标签:y2 int sum 51 坐标 x2 x1 dp

就是f[i][j]i和j表示的是第i行第j列
与别的没有区别
1.传纸条
往返两条路,实际上就是从起点分别走两条不相交的路,使其两条路上的总和最大
正常的话就用四层循环分别表示两条路各自点的坐标

f[x1][y1][x2][y2]=max(f[x1-1][y1][x2-1][y2],f[x1-1][y2][x2][y2-1],f[x1][y1-1][x2-1][y2],f[x1][y1-1][x2][y2-1])+a[x1][y1]+a[x2][y2];

四层循环
#include<bits/stdc++.h>
using namespace std;
int f[51][51][51][51];int a[51][51];
int n,m;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	for(int i1=1;i1<=n;i1++){
		for(int j1=1;j1<=m;j1++){
			for(int i2=1;i2<=n;i2++){
				for(int j2=1;j2<=m;j2++){
					if(j2!=j1&&i2!=i1) f[i1][j1][i2][j2]//两条路除了终点不能相交
					=max({f[i1-1][j1][i2-1][j2],f[i1-1][j1][i2][j2-1],f[i1][j1-1][i2-1][j2],f[i1][j1-1][i2][j2-1]})+a[i1][j1]+a[i2][j2];
				}
			}
		}
	}
	f[n][m][n][m]=max(f[n-1][m][n][m-1],f[n][m-1][n-1][m]);
	cout<<f[n][m][n][m];
}
但由于两条路都是仅能向右向下走,所以他们的步数一定是固定的,所以可以用i推出j来 所以

f[sum][x1][x2]=max(f[sum-1][x1-1][x2],f[sum-1][x1][x2-1],f[sum-1][x1][x2],f[sum-1][x1-1][x2-1])+a[x1][sum-x1]+a[x2][sum-x2];

优化
#include<bits/stdc++.h>
using namespace std;
int f[201][51][51];int a[51][51];
int n,m,ans;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	for(int k=2;k<=n+m-1;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				int j1=k+1-i;int j2=k+1-j;
				if(j1<1||j2<1) continue ;
				if(i==j) continue;
				f[k][i][j]=max({f[k-1][i][j],f[k-1][i-1][j],f[k-1][i][j-1],f[k-1][i-1][j-1]})+a[i][j1]+a[j][j2];
			}
		}
	}
	cout<<max(f[n+m-2][n][n-1],f[n+m-2][n-1][n])<<endl;
}
2.矩阵取数游戏 跟坐标好像没太大关系,更像是一个二维加一维的区间dp f[i][j][z]i表示起点,j为终点,z是某一层(因为每层互不干扰,所以说像强行加一维) 长度遍历2到len 找起点终点, f[i][j][z]=max(f[i+1][j][z]+a[z][i],f[i][j-1][z]+a[z][j]);
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
__int128 f[101][101][101],a[200][200],sum=0;
int n,m;
void print(__int128 num){
	if(num>9)
	print(num/10);
	cout<<(char)((num%10)+'0');
}
__int128 read(){
	__int128 res=0;
	char scan[1005];
	scanf("%s",scan);
	for(int i=0;i<strlen(scan);i++){
		res*=10;res+=scan[i]-'0';
	}
	return res;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]=read();
		}
	}
	for(int z=1;z<=n;z++){
		for(int len=1;len<=m;len++){
			for(int i=1;i+len-1<=m;i++){
				int j=i+len-1;
				f[i][j][z]=max(f[i+1][j][z]*2+a[z][i]*2,f[i][j-1][z]*2+a[z][j]*2);
			}
		}
		sum+=f[1][m][z];
	}
	print(sum);
}
3.晴天小猪 从上往下遍历,对于俩端的值特判一下 由于我存图存的是直角三角形,所以更新的位置会有不同;

f[i][j]=min(f[i-1][j],f[i-1][j-1])+a[i][j];
f[i][j]=min(f[i][j],f[i][j-1]+a[i][j]);(左往右)
f[i][j]=min(f[i][j],f[i][j+1]+a[i][j]);(右往左)

image

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int a[2020][2010];
int f[2022][2020];
int n;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin>>a[i][j];
		}
	}
	f[1][1]=a[1][1];
	for(int i=2;i<=n;i++){
		for(int j=2;j<i;j++){
			f[i][j]=min(f[i-1][j],f[i-1][j-1])+a[i][j];//更新本层数据(两端特判)
		}
			f[i][1]=min(f[i-1][i-1],f[i-1][1])+a[i][1];
			f[i][i]=min(f[i-1][i-1],f[i-1][1])+a[i][i];
		for(int j=2;j<=i;j++){//左右两边都遍历一下,听9G说是因为某些没有被上层更新的数据会影响后面数据的更新,所以要两边更新
			f[i][j]=min(f[i][j],f[i][j-1]+a[i][j]);
		}
		f[i][1]=min(f[i][1],f[i][i]+a[i][1]);
		for(int j=i-1;j>=1;j--){
			f[i][j]=min(f[i][j],f[i][j+1]+a[i][j]);
		}
		f[i][i]=min(f[i][i],f[i][1]+a[i][i]);
	}
	cout<<f[n][1];
}
4.盖房子

f[i][j]=min(f[i-1][j-1],f[i-1][j],f[i][j-1])+1;
这里利用了短板效应,f[i-1][j-1]表示能往左上方拓展的边长,f[i][j-1]表示往右拓展的长度,f[i-1][j]表示往上拓展的长度
而拓展的最小边长才能是正方形边长

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int a[2000][2000];
int n,m,maxn;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]){
				a[i][j]=min({a[i-1][j-1],a[i-1][j],a[i][j-1]})+1;
				maxn=max(maxn,a[i][j]);
			}
		}
	}
	cout<<maxn;
}

标签:y2,int,sum,51,坐标,x2,x1,dp
From: https://www.cnblogs.com/VigenereMiMaShiGeNiuBDeMiMaSuanFa/p/18018540

相关文章

  • 动态规划(六)——树形dp
    树形dp,又称树状dp,即在树上进行的dp,在设计动态规划算法时,一般就以节点从深到浅(子树从小到大)的顺序作为dp的“阶段”,dp的状态表示中,第一维通常是节点编号(代表以该节点为根的子树)。大多数时候,我们采用递归的方式实现树形动态规划。对于每个节点x,先递归在他的每个子节点上进行dp,在回溯......
  • 回顾复习之坐标DP
    定义坐标型动态规划一般是给定网格、序列,求满足条件的MAX或MIN。开数组时,dp[i]一般代表以ai结尾的满足条件的子序列,dp[i][j]代表以i、j结尾的满足条件的最优解例题数塔典中典变形晴天小猪历险记之Hill抓苹果免费馅饼矩阵取数描述传送门思路首先看出,每行的问题是独立......
  • 动态规划(五)——坐标dp
    传纸条题目描述小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小......
  • DP总结
    DP总结DP(动态规划)简介动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。由于动态规划并**不是某种具体的算法**,而是一种解决特定问题的方法,因此它会出现在各式各样的数据结构中,与之相关的题目种类也更为繁杂。DP基础1.必要前提 需要满足三个......
  • 区间dp
    Ø合并:意思就是将两个或多个部分进行整合,当然也可以反过来,也就是是将一个问题进行分解成两个或多个部分。Ø特征:能将问题分解成为两两合并的形式Ø求解:对整个问题设最优值,枚举合并点,将问题分解成为左右两个部分,最后将左右两个部分的最优值进行合并得到原问题的最优值。有点类......
  • 区间dp
    合并类动态规划合并:意思就是将两个或多个部分进行整合,当然也可以反过来,也就是是将一个问题进行分解成两个或多个部分。特征:能将问题分解成为两两合并的形式求解:对整个问题设最优值,枚举合并点,将问题分解成为左右两个部分,最后将左右两个部分的最优值进行合并得到原问题的最优......
  • 区间dp
    1.合并石子(1)排成一列的石子这个与合并果子唯一的不同就是只能合并相邻的石子,所以贪不得(怎么所有类型的动规要先上来搞贪心,有点diss贪心的感觉)f[i][j]表示i到j间合并的最大/最小得分;核心for(intlen=2;len<=n;len++){//表示长度2到len时的最大 for(inti=1;i+len-1<=n;i++)......
  • 背包dp
    01背包描述:有n个物品,每个物品只有一件,第i个物品体积为vi,价格为ci。现在有一个体积为V的背包,请你从n件物品里选出若干件放进背包里,使得背包里的物品价值最大。思路:01背包的特点是:每种物品只有一件,可以选择放或不放。我们可以根据此特点进行动态规划(DP),设f[i][j]表示前i件物品放......
  • 动态规划-DP 完整版
    动态规划学完了五大基础dp做个简单总结dp特征动态规划问题首要是找到做题的目的是求最大/小值还是其他;其二要确定问题的状态转移方程这是关键;第三为dp数组找到边界、最后检查是否需要结合其他相关知识如树dfs等;别忘了检查多测输入数组变量置零等易错点。......
  • 线性dp
    线性动态规划:不用多说,主要应用于求上升子序列,下降子序列等直接看例题:样例输入:13791638243718441921226315样例输出:max=879161819212263解:#include<bits/stdc++.h>usingnamespacestd;constintMAX=1050;intn,ans;intf[MAX],......