2021.06.19 DP-方格取数 + 花店橱窗布置
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;
}