2021.06.19 DP-方格取數 + 花店櫥窗佈置
阿新 • • 發佈:2021-06-19
T1
題意
在\(A_{i,j}\)內找到從\(A_{1,1}\)到\(A_{n,n}\)的兩條路徑,使兩條路徑權值和最大
分析
一道比較經典的題。
先考慮只有一條路徑的情況。
不難發現,有\(dp[i][j]=max\{dp[i-1][j],dp[i][j-1]\}+a[i][j]\)(由左/上轉移過來)
考慮兩條路徑的情況:
可以再開兩維,\([k][p]\)的後兩維表示另一條路徑走到\((k,p)\)的權值。
注:因為兩條道路不能重合,所以寫為:if(i != k && j != q) dp[i][j][k][q] += a[k][q];
(如果兩個不在同一點,則加上新點的權值)
相似題目:傳紙條
程式碼
#include <bits/stdc++.h> #define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout) using namespace std; typedef long long ll; typedef unsigned long long ull; const int INF = 0x3f3f3f3f , N = 15; inline ll read(){ ll ret = 0 ; char ch = ' ' , c = getchar(); while(!(c >= '0' && c <= '9'))ch = c , c = getchar(); while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar(); return ch == '-' ? -ret : ret; } int a[15][15],n; int dp[N][N][N][N]; inline int Max(int a,int b,int c,int d){return max(max(a,b),max(c,d));} signed main(){ n = read(); while(1){ int x = read() , y = read() , p = read(); if(!x && !y)break; a[x][y] = p; } for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= n ; j ++) printf("%d%c",a[i][j]," \n"[j==n]); for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= n ; j ++) for(int k = 1 ; k <= n ; k ++) for(int q = 1 ; q <= n ; q ++){ dp[i][j][k][q] = max(dp[i][j][k][q],Max(dp[i-1][j][k-1][q],dp[i-1][j][k][q-1],dp[i][j-1][k-1][q],dp[i][j-1][k][q-1])+a[i][j]); if(i != k && j != q) dp[i][j][k][q] += a[k][q]; } printf("%d",dp[n][n][n][n]); return 0; }
T2
題意
給定\(A_{n,m}\)的矩陣,找到\(\forall 1 < i \le n且1\le k < j \le m,A_{i-1,k}\to A_{i,j}\)的路徑權值最大的,並輸出路徑
分析
同前,易得到\(dp[i][j] = dp[i-1][k] + a[i][j]\)
記錄一下路徑並輸出即可。
注:
- 因為會選取到\((1,1)\),而"正常的DP"中不會遍歷到這一點,導致錯誤!!
->k從0開始列舉
- 因為資料可能是負值,所以memset()需要賦為\(-\infty\)
程式碼
#include <bits/stdc++.h> #define fo(a) freopen(a".in","r",stdin)//,freopen(a".out","w",stdout) using namespace std; typedef long long ll; typedef unsigned long long ull; const int INF = 0x3f3f3f3f , N = 105; inline ll read(){ ll ret = 0 ; char ch = ' ' , c = getchar(); while(!(c >= '0' && c <= '9'))ch = c , c = getchar(); while(c >= '0' && c <= '9')ret = (ret << 1) + (ret << 3) + c - '0' , c = getchar(); return ch == '-' ? -ret : ret; } int n,m; int a[N][N],dp[N][N],pre[N][N]; void print(int i,int j){ if(!i)return; print(i-1,pre[i][j]); printf("%d ",j); } signed main(){ // fo("a"); memset(dp,-0x3f,sizeof(dp)); n = read() , m = read(); for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= m ; j ++) a[i][j] = read(); for(int i = 0 ; i <= m ; i ++) dp[0][i] = 0; for(int i = 1 ; i <= n ; i ++) for(int j = i ; j <= m - n + i ; j ++) for(int k = 0 ; k < j ; k ++) if(dp[i][j] < dp[i-1][k] + a[i][j]) dp[i][j] = dp[i-1][k] + a[i][j], pre[i][j] = k; int maxn = -INF,pos; for(int i = 1 ; i <= m ; i ++) if(maxn < dp[n][i]) maxn = dp[n][i],pos = i; printf("%d\n",maxn); print(n,pos); return 0; }