[DP 区间 高精]矩阵取数

这篇博客详细介绍了如何使用动态规划解决矩阵取数游戏问题。每行独立考虑,通过状态转移方程`f[i][j]=max(f[i+1][j]+2^kg[i], f[i][j-1]+2^kg[r])`递推求解最大值,其中`g[i]`是矩阵中元素的权重。博客提供了两种实现方式,分别是迭代和递归加记忆化,并给出了完整的C++代码实现。
摘要由CSDN通过智能技术生成

[DP 区间 高精]矩阵取数

题目

在这里插入图片描述

思路

可以发现每行独立,所以单独考虑每行的max
定义 f [ i ] [ j ] f[i][j] f[i][j]为从i到j进行取数得到的最大值
首先我们不考虑权值 2 i , 可 以 得 到 以 下 状 态 转 移 2^i,可以得到以下状态转移 2i,
f [ i ] [ j ] = m a x ( f [ i + 1 ] [ j ] + w [ i ] , f [ i ] [ j − 1 ] + w [ r ] ) f[i][j]=max(f[i+1][j]+w[i],f[i][j-1]+w[r]) f[i][j]=max(f[i+1][j]+w[i],f[i][j1]+w[r])
然后考虑权值,我们用小数据举例
f [ 1 ] [ 1 ] = 2 ∗ g [ 1 ] , f [ 2 ] [ 2 ] = 2 ∗ g [ 2 ] , f [ 3 ] [ 3 ] = 2 ∗ g [ 3 ] f[1][1]=2*g[1],f[2][2]=2*g[2],f[3][3]=2*g[3] f[1][1]=2g[1],f[2][2]=2g[2],f[3][3]=2g[3]
f [ 1 ] [ 2 ] = m a x ( 4 ∗ g [ 1 ] + 2 ∗ g [ 2 ] , 2 ∗ g [ 1 ] + 4 ∗ g [ 2 ] ) = m a x ( 2 ∗ f [ 1 ] + 2 ∗ g [ 2 ] , 2 ∗ f [ 2 ] [ 2 ] + 2 ∗ g [ 2 ] ) f[1][2]=max(4*g[1]+2*g[2],2*g[1]+4*g[2])=max(2*f[1]+2*g[2],2*f[2][2]+2*g[2]) f[1][2]=max(4g[1]+2g[2],2g[1]+4g[2])=max(2f[1]+2g[2],2f[2][2]+2g[2])
f [ l ] [ r ] = m a x ( f [ l + 1 ] [ r ] ∗ 2 + 2 ∗ g [ l ] , f [ l ] [ r − 1 ] ∗ 2 + 2 ∗ g [ r ] ) f[l][r]=max(f[l+1][r]*2+2*g[l],f[l][r-1]*2+2*g[r]) f[l][r]=max(f[l+1][r]2+2g[l],f[l][r1]2+2g[r])

写dp的话需要牢记的一点是,如果是for循环迭代的形式,思路应该是反过来的,应该是从等号右边转移到左边应该怎么样。

递归写法状态转移
f [ i ] [ j ] = m a x ( f [ i + 1 ] [ j ] + g [ i ] ∗ 2 k , f [ i ] [ j − 1 ] + g [ j ] ∗ 2 k ) f[i][j]=max(f[i+1][j]+g[i]*2^k,f[i][j-1]+g[j]*2^k) f[i][j]=max(f[i+1][j]+g[i]2k,f[i][j1]+g[j]2k)

代码

// Problem: P1005 [NOIP2007 提高组] 矩阵取数游戏
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1005
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
//#define MULINPUT
/*DATA & KEY

*/
int T;
const int N=100;
LL g[N][N];
__int128 f[N][N][N];
__int128 ans;
LL fp(LL a,LL b){
	LL res=1;
	while(b){
		if(b&1)res=res*a;
		b>>=1;
		a=a*a;
	}
	return res;
}
void solve(int C)
{
	//NEW DATA CLEAN
	
	//NOTE!!!
	LL n,m;cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>g[i][j];
	for(int i=1;i<=n;i++){
		for(int len=1;len<=m;len++){
			for(int l=1;l+len-1<=m;l++){
				int r=l+len-1;
				f[i][l][r]=max(2*f[i][l+1][r]+2*g[i][l],2*f[i][l][r-1]+2*g[i][r]);
			}
		}
	}
	for(int i=1;i<=n;i++)ans+=f[i][1][m];
	print(ans);
}

int main()
{
	#ifdef MULINPUT
		scanf("%d",&T);
		for(int i=1;i<=T;i++)solve(i);
	#else
		solve(1);
	#endif
	return 0;
}

递归+记忆化写法

// Problem: P1005 [NOIP2007 提高组] 矩阵取数游戏
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1005
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// FishingRod

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
//#define MULINPUT
/*DATA & KEY

*/
int T;
const int N=100;
LL g[N][N];
__int128 f[N][N][N];
__int128 q[N];
__int128 n,m,ans;
__int128 dfs(int i,int l,int r){
	if(f[i][l][r])return f[i][l][r];
	if(l==r)return g[i][l]*((__int128)1<<m);
	__int128 k=m-(r-l);
	return f[i][l][r]=max(dfs(i,l+1,r)+((__int128)1<<k)*g[i][l],dfs(i,l,r-1)+((__int128)1<<k)*g[i][r]);
}
void solve(int C)
{
	//NEW DATA CLEAN
	
	//NOTE!!!
	n=read(),m=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>g[i][j];
	for(int i=1;i<=n;i++)ans+=dfs(i,1,m);
	print(ans);
}

int main()
{
	#ifdef MULINPUT
		scanf("%d",&T);
		for(int i=1;i<=T;i++)solve(i);
	#else
		solve(1);
	#endif
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值