2021/06/19模拟 - 书上例题*2
T1方格取数
如图的图:
很显然的一道动态规划题目
策略:四重循环表示从x1到y1的最大值+x2到y2的最大值
注意:不能重复走!
所以状态转移方程:
sum[x1][y1][x2][y2] = max(max(sum[x1-1][y1][x2][y2-1],sum[x1][y1-1][x2-1][y2]),max(sum[x1-1][y1][x2-1][y2],sum[x1][y1-1][x2][y2-1]))+MAP[x2][y2]+MAP[x1][y1];
if(x1 == x2 && y1 == y2)sum[x1][y1][x2][y2] -= MAP[x2][y2];
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
#define ll long long
#define SZJ_IN freopen("Pane.in","r",stdin)
#define SZJ_OUT freopen("Pane.out","w",stdout)
using namespace std;
const int MAXN = 51;
ll MAP[MAXN][MAXN];
ll sum[MAXN][MAXN][MAXN][MAXN];
ll n;
int main(){
//SZJ_IN;SZJ_OUT;
memset(sum,0,sizeof(sum));
memset(MAP,0,sizeof(MAP));
scanf("%lld",&n);
for(int kk = 1 ; ; kk++){
ll i,j,num; // i行j列,num
scanf("%lld %lld %lld",&i,&j,&num);
if(i==0&&j==0&&num==0)break;
MAP[i][j] = num;
}
// for(int x1 = 1 ; x1 <= n ; x1++){
// for(int y1 = 1 ; y1 <= n ; y1++){
// for(int x2 = 1 ; x2 <= x1 ; x2++){
// for(int y2 = 1 ; y2 <= y1 ; y2++){
// if(sum[x1][y1][x2][y2] <= sum[x1-1][y1][x2][y2]){
// sum[x1][y1][x2][y2] = max(sum[x1][y1][x2][y2],sum[x1-1][y1][x2][y2]+MAP[x1-1][y1]);
// }
// if(sum[x1][y1][x2][y2] <= sum[x1][y1-1][x2][y2]){
// sum[x1][y1][x2][y2] = max(sum[x1][y1][x2][y2],sum[x1][y1-1][x2][y2]+MAP[x1][y1-1]);
// }
// if(sum[x1][y1][x2][y2] <= sum[x1][y1][x2-1][y2]){
// sum[x1][y1][x2][y2] = max(sum[x1][y1][x2][y2],sum[x1][y1][x2-1][y2]+MAP[x2-1][y2]);
// }
// if(sum[x1][y1][x2][y2] <= sum[x1][y1][x2][y2-1]){
// sum[x1][y1][x2][y2] = max(sum[x1][y1][x2][y2],sum[x1][y1][x2][y2-1]+MAP[x2][y2-1]);
// }
// }
// }
// }
// }
for(int x1 = 1 ; x1 <= n ; x1++){
for(int y1 = 1 ; y1 <= n ; y1++){
for(int x2 = 1 ; x2 <= n ; x2++){
for(int y2 = 1 ; y2 <= n ; y2++){
sum[x1][y1][x2][y2] = max(max(sum[x1-1][y1][x2][y2-1],sum[x1][y1-1][x2-1][y2]),max(sum[x1-1][y1][x2-1][y2],sum[x1][y1-1][x2][y2-1]))+MAP[x2][y2]+MAP[x1][y1];
if(x1 == x2 && y1 == y2)sum[x1][y1][x2][y2] -= MAP[x2][y2];
}
}
}
}
// for(int i = 1 ; i <= n ; i++){
// for(int j = 1 ; j <= n ; j++){
// printf("%lld ",MAP[i][j]);
// }
// printf("\n");
// }
printf("%lld",sum[n][n][n][n]);
return 0;
}
/*
INSERT:
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
ANS:
67
*/
中间的注释是另一种gg在题目中说的4层if判断?!
T2橱窗布置
首先审题:
1.题目中I<J那么I的花就必须放在J的左侧,那么可以直接使用记忆化搜索 (暴力) 每次枚举一层,从上一层便利到的点的右边进行下一次便利,边界直接return
2.所谓记忆化搜索都可以用DP解决,不错的↓
DP:
1.dp定义:用dp[i][j]表示1-i束花放到j花瓶的最大值
2.状态转移方程:dp[i][j] = max(dp[i-1][k-1]+a[i][k]),i<=k<=j
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
#define ll long long
#define SZJ_IN freopen("flower.in","r",stdin)
#define SZJ_OUT freopen("flower.out","w",stdout)
using namespace std;
const int MAXF = 110,MAXV = 110;
ll f,v;
ll a[MAXF][MAXV];
ll dp[MAXF][MAXV];
//bool vis[MAXV];
//int DP(int F,int k){
// for(int i = F ; i <= f ; i++){
// sum[F] = max(sum[F],sum[F]+DP(F+1,i));
// }
//}
void print(int i,int j){
int n;
if(i > 0){
n = i;
while(dp[i][n]!=j){
n++;
}
print(i-1,j-a[i][n]);
printf("%d ",n);
}
}
int main(){
//SZJ_IN;SZJ_OUT;
memset(dp,0,sizeof(dp));
scanf("%lld %lld",&f,&v);
for(int i = 1 ; i <= f ; i++){
for(int j = 1 ; j <= v ; j++){
scanf("%lld",&a[i][j]);
}
}
for(int i = 1 ; i <= v ; i++){
dp[1][i] = a[1][i];
}
for(int i = 1 ; i <= f ; i++){
for(int j = i ; j <= v-f+i ; j++){
for(int k = i ; k <= j ; k++){
dp[i][j] = max(dp[i][j],dp[i-1][k-1]+a[i][k]);
}
}
}
printf("%lld\n",dp[f][v]);
print(f,dp[f][v]);
// print(f,v);
// for(int i = 1 ; i <= f ; i++){
// for(int j = 1 ; j <= v ; j++){
// printf("%lld ",a[i][j]);
// }
// printf("\n");
// }
// DP(1,1);
return 0;
}
/*
INSERT:
3 5
7 23 -5 -24 16
5 21 -4 10 23
-21 5 -4 -20 20
ANS:
53
2 4 5
*/
输出:
void print(int i,int j){
int n;
if(i > 0){
n = i;
while(dp[i][n]!=j){
n++;
}
print(i-1,j-a[i][n]);
printf("%d ",n);
}
}
觉得gg今天在diss我,所以以后要多注意基础
不要抢AC(滑稽)
✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿✿