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,1)\),而"正常的DP"中不会遍历到这一点,导致错误!!->k从0开始枚举
  2. 因为数据可能是负值,所以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;
}
posted @ 2021-06-19 19:26  Last-Order  阅读(67)  评论(0编辑  收藏  举报