luogu 1006 1004 傳紙條 方格取數
阿新 • • 發佈:2018-11-03
傳紙條: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; }