NOIP 2000 方格取数 dp

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP 2000 方格取数 dp相关的知识,希望对你有一定的参考价值。

题目链接

题意:
有n*n的方格,有些格子上有数,有些格子上没有数(可以认为是0),现从(1,1)走到(n,n)走两次,走过之后,上面的数就会变为0,问两次走的路径取得的数字之和最大为多少?

思路:
状态表示:
d p [ i 1 ] [ i 2 ] [ k ] dp[i1][i2][k] dp[i1][i2][k]表示从(1,1)开始两条路径分别走到 ( i 1 , k − i 1 ) , ( i 2 , k − i 2 ) (i1,k-i1),(i2,k-i2) (i1,ki1),(i2,ki2)取得的数字的最大值。

其实 k = i 1 + j 1 = i 2 + j 2 k=i1+j1=i2+j2 k=i1+j1=i2+j2,我们让两个路径的横纵坐标加和相同,可以理解为步长(但不是步长),步长相同刚好能枚举在同一时刻的状态,因为他们走的步数一样嘛。
有步长了,就可以根据横坐标推出纵坐标了。所以就很巧妙

当前状态可由四种情况来转移:

上一个状态都是步长减一,表示的是两条路径步长都减去一,两条路径是同时进行的。

  • d p [ i 1 − 1 ] [ i 1 − 1 ] [ k − 1 ] dp[i1-1][i1-1][k-1] dp[i11][i11][k1]表示两条路径都是从当前点的上方转移而来的,当前点指的是两条路径分别对应的当前点,不一定一样
  • d p [ i 1 − 1 ] [ i 2 ] [ k − 1 ] dp[i1-1][i2][k-1] dp[i11][i2][k1]表示第一条路径从当前点(第一条路径的当前点)的上方转移而来的,第二条路径从当前点(第二条路径的当前点)的左边转移而来
  • d p [ i 1 ] [ i 2 − 1 ] [ k − 1 ] dp[i1][i2-1][k-1] dp[i1][i21][k1]表示第一条路径从当前点(第一条路径的当前点)的左边转移而来的,第二条路径从当前点(第二条路径的当前点)的上方转移而来
  • d p [ i 1 ] [ i 2 ] [ k − 1 ] dp[i1][i2][k-1] dp[i1][i2][k1]表示两条路径都是从当前点的左边转移而来的,当前点指的是两条路径分别对应的当前点,不一定一样

状态来自这四种情况

所以只要取他们的最大值就行了

注意:
都是从上方或者左边转移的,他们不一定来自同一个点,所以只有 i 1 = i 2 i1=i2 i1=i2时,他们才来自同一个点,这时候,取的数就会只有一个,因为一条路径取过之后方格上的数就会变为0

#include<bits/stdc++.h>
using namespace std;
int a[15][15],dp[15][15][30];

int main()
{
    int n;cin>>n;
    int x,y,num;
    //都为0时才结束
    while(cin>>x>>y>>num,x||y||num)
        a[x][y]=num;
    for(int k=2;k<=n+n;k++)//k=i1+j1=i2+j2
    {
        for(int i1=1;i1<=n;i1++)
        {
            for(int i2=1;i2<=n;i2++)
            {
                int j1=k-i1,j2=k-i2;
                if(j1>=1&&j1<=n&&j2>=1&&j2<=n)//纵坐标必须满足条件
                {
                    int w = a[i1][j1];
                    if(i1!=i2) w+=a[i2][j2];//不是同一个点就加两个方格对应的数
                    int &q = dp[i1][i2][k];//太长了,用引用减少代码量
                    q=max(q,dp[i1-1][i2-1][k-1]+w);
                    q=max(q,dp[i1-1][i2][k-1]+w);
                    q=max(q,dp[i1][i2-1][k-1]+w);
                    q=max(q,dp[i1][i2][k-1]+w);
                }
            }
        }
    }
    cout<<dp[n][n][n+n]<<'\\n';
    return 0;
}

以上是关于NOIP 2000 方格取数 dp的主要内容,如果未能解决你的问题,请参考以下文章

Codevs 1043 方格取数

codevs 2853 方格游戏--棋盘dp

DP洛谷1004方格取数

HDU 1565 方格取数

dp算法之方格取数

洛谷 2774方格取数问题 | 状压DP