NOIP2000提高 方格取数 三维DP

题目链接

https://www.luogu.com.cn/problem/P1004

题意

n阶方阵,每个格子有值,从左上走到右下两次,不能取走同一格子的值两次,求取到的值的最大总和

思路

三维dp同时维护两个状态,dp[k][i1][i2]代表总共走了k-2步(为了编码方便),第一次处于i1行,第二次处于i2行时能取的最大值。

因为步数固定了,所以列号也固定了,考虑转移方程,一共四个方向可以走到当前情况:第一次向右,第二次向下;第一次向下,第二次向右;第一次向下,第二次向下;第一次向右,第二次向右;所以四种状态取最大值即可。

再考虑如何处理不重复的问题,因为不可能走回头路, 所以我们只需要处理每走一步时两次不要取同一个数就可以了,dp第一维为k时,当且仅当i1==i2时到了同一个格子,这样的话只要把当前状态加上w[i1][k-i1]即可,若不相等,则需要加上w[i1][k-i1]和w[i2][k-i2]

教训/收获

某一式子重复多次出现时,可以用引用创建别名,方便编码

代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=100500;
	const int inf=0x3f3f3f3f;
	int n,m;
	template <typename T>
	void read(T &x){
    	x=0;
    	char ch=getchar();
    	ll f=1;
	    while(!isdigit(ch)){
	        if(ch=='-')
	            f*=-1;
	        ch=getchar();
	    }
	    while(isdigit(ch)){
	        x=x*10+ch-48;
	        ch=getchar();
	    }
	    x*=f;
	}
	int dp[25][15][15],a[15][15];
	int main(){
		IOS
		//freopen("D:\\VScode\\IO\\in.txt","r",stdin);
		//freopen("D:\\VScode\\IO\\out.txt","w",stdout);
		int n;
		cin>>n;
		int x,y,z;
		while(cin>>x>>y>>z){
			if(x==0&&y==0&&z==0)
				break;
			a[x][y]=z;
		}
		for(int k=2;k<=2*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||j2<1||j1>n||j2>n)
						continue;
					int w=a[i1][j1];
					if(j1!=j2)
						w+=a[i2][j2];
					int &x=dp[k][i1][i2];
					x=max(x,dp[k-1][i1-1][i2]+w);
					x=max(x,dp[k-1][i1][i2-1]+w);
					x=max(x,dp[k-1][i1][i2]+w);
					x=max(x,dp[k-1][i1-1][i2-1]+w);
				}
			}
		}
		cout<<dp[2*n][n][n];
	}

	

	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值