1. 程式人生 > >luogu 1006 1004 傳紙條 方格取數

luogu 1006 1004 傳紙條 方格取數

傳紙條:https://www.luogu.org/problemnew/show/P1006

方格取數:https://www.luogu.org/problemnew/show/P1004

 

這兩道題一樣的……所以我放在一起整理

方格取數比較簡單,記住一條公式,方格任意一點:i+j=k+2。對於這道題,因為開始從左上角走,所以k是走的步數,所以我們只需要一個三維dp,f[k][i][j]表示走了k步,第一個人在第i列,第二個人在第j列,然後根據公式,橫座標也推出來了,所以複雜度只是三次方!然後對於取完數變0這個操作,只需要當橫縱座標都相等時,只取一個就行了。

 

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
int a[15][15],f[15<<1][15][15],n;
using namespace std;
int main()
{
    cin>>n;
    int x,y,z;
    while(scanf("%d %d %d",&x,&y,&z))
    {
        if(x==0&&y==0&&z==0)break;
        a[x][y]=z;
    
    }
    f[0][1][1]=a[1][1];
    for(int k=1;k<=2*n-2;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                int x=k+2-i,y=k+2-j;
                if(x<1||j<1)continue;//判越界
                f[k][i][j]=max(f[k-1][i][j],max(f[k-1][i-1][j],max(f[k-1][i][j-1],f[k-1][i-1][j-1])))+a[i][x]+a[j][y];
                if(i==j&&x==y)f[k][i][j]-=a[i][x];
            }
        }
    }
    cout<<f[2*n-2][n][n];
} 

傳紙條程式碼其實差不多的,基本思路也就像上面那個一樣。但是它多了一個條件,就是走過了一個格子,另一個人是不能再走的,相當於封路了。這個時候我們要把列強制不相等嗎?其實不是的,像上面那樣,走到一起就減去就好了。為什麼可以這樣呢?

 

https://www.luogu.org/discuss/show?postid=63900

 

引用了luogu的xeonz1的討論發言

 

#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 55
using namespace std;
int f[2 * maxn][maxn][maxn];
int a[maxn][maxn];
int n,m;

int max_ele(int a,int b,int c,int d){
    if (b>a)
        a = b;
    if (c>a)
        a = c;
    if (d>a)
        a = d;
    return a;
}

int main(){
    cin >> n >> m;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            cin >> a[i][j];
    for (int k=1;k<=n+m-1;k++)
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++){
            	int xx=k-i+2,yy=k-j+2;
                if (k-i+2<1 || k-j+2<1) //這裡是判斷縱座標的合法性,如果縱座標不合法那就跳過去
                    continue;
                 f[k][i][j] = max_ele(f[k-1][i][j],f[k-1][i-1][j-1],f[k-1][i][j-1],f[k-1][i-1][j]) + a[i][xx] + a[j][yy];
                if (i==j&&xx==yy) //判斷重合路徑
                    f[k][i][j]-=a[i][xx];
            }

    cout << f[n+m-2][n][n] << endl;
    return 0;
}