多进程DP

题1:NYOJ 61(传纸条),先看一个人的情况,DP[i][j]表示纸条到达(i,j)的时候好心程度之和的最大值,那么由于只能向下或者向右走,那么到达(i,j)位置可能是由(i-1,j)下移一步或者由(i,j-1)位置,右移一步得到,所以动态转移方程为:DP[i][j]=max(DP[i-1][j],DP[i][j-1])+G[i][j]。(G[i][j]表示(i,j)这个位置的人的好心程度)。

题目的意思是先从位置(0,0)传到(n,m),再由(n,m)传到(0,0),那么我可以假设从(0,0)这个位置由两条路径同时向(n,m)传,只要这两条路径中不含相同的点,则结果也是一样的,用DP[i][j][p][q]表示一条路径由(0,0)传到(i,j)和另一条路径由(0,0)传到(p,q)之间的好心程度只和的最大值,最终结果都是到达(n,m),所以只需输出DP[n][m][n][m]即可。

动态规划方程为:DP[i][j][p][q]=max(DP[i-1][j][p-1][q],DP[i][j-1][p-1][q],DP[i-1][j][p][q-1],DP[i][j-1][p][q-1])+G[i][j]+G[p][q]

由于每次都只能是向下或者向右移动,那么位置变化也只能是纵坐标+1或者横坐标+1,又是从(0,0)开始,所以若到达(i,j)位置,那么到达(i,j)位置经过的步数为i+j,所以经过相同的步数后必定满足:i+j=p+q。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=52;
#define max(a,b) (a)>(b)?(a):(b)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int n,m,G[MAX][MAX],DP[MAX][MAX][MAX][MAX];
int Max(int a,int b,int c,int d)
{   return max(max(a,b),max(c,d)); 
}
int main()
{   int Case;
    CLR(DP,0);
    scanf("%d",&Case);
    while(Case--)
    {   scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&G[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                for(int p=i+1,q;p<=n;p++)
                {   int q=i+j-p; 
                    if(q<=0) continue; //这条语句一定要加 
                    DP[i][j][p][q]=Max(DP[i-1][j][p-1][q],DP[i-1][j][p][q-1],
                                       DP[i][j-1][p-1][q],DP[i][j-1][p][q-1])
                                       +G[i][j]+G[p][q];               
                }
        int res=Max(DP[n-1][m][n-1][m],DP[n-1][m][n][m-1],
                    DP[n][m-1][n-1][m],DP[n][m-1][n][m-1]);       
       printf("%d\n",res); 
    } 
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值