NYOJ 61 传纸条

本文介绍了一种将四维动态规划问题通过优化减少至三维的方法,并提供了详细的代码示例。通过对状态表示进行调整,利用步数和横坐标的特性来减少维度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://acm.nyist.net/JudgeOnline/problem.php?pid=61

四维的DP ,但是用四维,肯定会超时。

从图中我们可以看到,在K 时刻,A 位于(i,ii ),B 位于(j,jj),那么在K -1 时刻 A 有两种状态,A 1  和A 2 ,B 有两种状态 B 1 和B 2  ,两两组合就有四种状态,所以K 时刻的最优解可由K -1 时刻四种状态的最优解加上,A  和  B 的值取得。

动态转移方程为:

dp[i][ii][j][jj] = max( dp[i][ii-1][j][jj-1] , dp[i][ii-1][j-1][jj] , dp[i-1][ii][j][jj-1] , dp[i-1][ii][j-1][jj] ) + map[i][ii] + map[j][jj];

所以我们可以直接枚举四个变量。但是要注意  A  和 B 点不能再同一点上。

但是无疑这种方法是超时的。四维的dp 数据量太大了

#include <stdio.h> 
#include <string.h> 
int dp[53][53][53][53];
int map[53][53];
int max(int a,int b)
{
  return a>b? a:b;    
}
 
int main()
{
  int T,row,col,i,j,ii,jj,k,t1,t2,ans;
  
  scanf("%d",&T);
   
    do
    {
       scanf("%d%d",&row,&col);          
        
       for(i = 1 ; i <= row ; ++i)          
       for(j = 1 ; j <= col ; ++j)
       scanf("%d",&map[i][j]);   
       
       for(i = 1 ; i <=row ; ++i)
       for(j = 1 ; j <= row ; ++j)
       for(ii = 1 ; ii <= col ; ++ii) 
       for(jj = 1 ; jj <= col ; ++jj)
       if(i != j || ii != jj)
       {
             t1 = max(dp[i][ii-1][j][jj-1],dp[i][ii-1][j-1][jj]);     
             t2 = max(dp[i-1][ii][j][jj-1],dp[i-1][ii][j-1][jj]);  
             dp[i][ii][j][jj] = max(t1,t2) + map[i][ii] + map[j][jj];
       }      
              
       ans = max(dp[row][col-1][row-1][col],dp[row-1][col][row][col-1]);       
       printf("%d\n",ans);       
                  
    }while(--T);
      
 // system("pause");
  return 0;    
}

i + ii - 1  明显是等于  i - 1 + ii 的,所以,我们标记一个点的时候只要一个步数和一个横坐标就行了。这样就把四维的降到了三位。

 
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[110][110][110];
int map[55][55];
int main()
{
    int N,n,m,i,j,ii,jj,k,s,t,all;
    cin>>N;
    while(N--)
    {
        memset(dp,0,sizeof(dp));
        memset(map,0,sizeof(map));
        cin>>m>>n;
        for(i = 1; i <= m; i++)
        for(j = 1; j <= n; j++)
        {
            cin>>map[i][j];
        }
        all = m+n;
        for(k = 2; k <= all; k++)
        for(i = 1; i <= m; i++)
        for(j = 1; j <= m; j++)
        {
            if(i != j && i <= k && j <=k)
            {
                s = max(dp[k-1][i-1][j],dp[k-1][i-1][j-1]);
                t = max(dp[k-1][i][j],dp[k-1][i][j-1]);
                dp[k][i][j] = max(s,t) + map[i][k-i] + map[j][k-j];
            }
        }
        int ans = max(dp[all-1][m][m-1] , dp[all-1][m-1][m]);
        cout<<ans<<endl;
    }
    return 0;
}
        

还有一题与之非常相似。

http://ayit.acmclub.com/index.php?app=problem_title&id=233&problem_id=21491

知识A 点 和B 点能到达同一点。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[110][110][110],map[55][55];

int main()
{
    int n,m,s,t,i,j,k;
    cin>>m>>n;
    for(i = 1; i <= m; i++)
    for(j = 1; j <= n; j++)
    cin>>map[i][j];
    int all = m+ n;
    for(k = 2; k <= all; k++)
    for(i = 1; i <= m; i++)
    for(j = 1; j <= m; j++)
    if(i != j && i <= k && j <= k)
    {
        s = max(dp[k-1][i][j-1],dp[k-1][i-1][j]);
        t = max(dp[k-1][i][j],dp[k-1][i-1][j-1]);
        dp[k][i][j] = max(s,t) + map[i][k-i] + map[j][k-j];
    }
    int ans = max(dp[all-1][m][m-1],dp[all-1][m-1][m]);
    cout<<ans<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值