洛谷 P7266 [BalticOI 2000] Honeycomb Problem 的题解

题目大意

略。

思路

这题挺难的!

观察数据范围,发现 O ( n 3 ) O(n^3) O(n3) 最适合,于是选择暴力 dp。

d p i , j , 0 / 1 dp_{i,j,0/1} dpi,j,0/1 表示当前走到了第 i i i 行,第 j j j 列没交换/交换数字的最大权值和。

我们发现蜂窝图的行和列都是 2 × n − 1 2 × n - 1 2×n1,所以得开 d p [ 200 ] [ 200 ] [ 2 ] dp[200][200][2] dp[200][200][2]。有点烦人的是输入,但是找一下规律其实也没那么难。主要是先输入上半部分,再输入下半部分:

for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n + i - 1; j++) {
			cin >> a[i][j];
		}
	for(int i = 1; i <= n - 1; i++)
		for(int j = 1; j <= 2 * n - i - 1; j++) {
			cin >> a[i + n][j];
		}

然后我们来讨论一下状态转移方程。

转移方程主要分成两种情况(为了方便,数组就不用 LaTeX \LaTeX LATEX 了):

  • 从第 1 1 1 行到第 n n n 行(列数递增),易得转移方程: d p [ i ] [ j ] [ 0 ] = max ⁡ ( d p [ i − 1 ] [ j ] [ 0 ] , d p [ i − 1 ] [ j − 1 ] [ 0 ] ) + a [ i ] [ j ] dp[i][j][0] = \max(dp[i-1][j][0],dp[i-1][j-1][0])+a[i][j] dp[i][j][0]=max(dp[i1][j][0],dp[i1][j1][0])+a[i][j] d p [ i ] [ j ] [ 1 ] = max ⁡ ( max ⁡ ( d p [ i − 1 ] [ j ] [ 1 ] , d p [ i − 1 ] [ j − 1 ] [ 1 ] ) + a [ i ] [ j ] ) , max ⁡ ( d p [ i − 1 ] [ j ] [ 0 ] , d p [ i − 1 ] [ j − 1 ] [ 0 ] ) + r o w m a x [ i ] ) dp[i][j][1] = \max(\max(dp[i-1][j][1],dp[i-1][j-1][1])+a[i][j]),\max(dp[i-1][j][0],dp[i-1][j-1][0])+rowmax[i]) dp[i][j][1]=max(max(dp[i1][j][1],dp[i1][j1][1])+a[i][j]),max(dp[i1][j][0],dp[i1][j1][0])+rowmax[i])

  • 从第 n + 1 n + 1 n+1 行到第 2 × n − 1 2 × n - 1 2×n1 行(列数递减),状态转移方程跟上面的没啥两样,建议自己想,实在想不出来看

这里面的 r o w m a x i rowmax_i rowmaxi 表示第 i i i 行最大的值。我们用贪心,如果这一行要换值,那么就把值换成最大的。

最后取 d p n × 2 − 1 , i , 1 dp_{n×2-1,i,1} dpn×21,i,1 的最大值即可。

#include <bits/stdc++.h>
using namespace std;
int n, ans = 0;
int row[207];
int a[207][207];
int dp[207][207][2];
int main() {
	cin >> n;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n + i - 1; j++) {
			cin >> a[i][j];
			row[i] = max(row[i], a[i][j]);
		}
	for(int i = 1; i <= n - 1; i++)
		for(int j = 1; j <= 2 * n - i - 1; j++) {
			cin >> a[i + n][j];
			row[i + n] = max(row[i + n], a[i + n][j]);
		}
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n + i - 1; j++) {
			dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j - 1][0]) + a[i][j];
			dp[i][j][1] = max(max(dp[i - 1][j][1], dp[i - 1][j - 1][1]) + a[i][j], max(dp[i - 1][j][0], dp[i - 1][j - 1][0]) + row[i]);
		}
	for(int i = 1; i <= n - 1; i++)
		for(int j = 1; j <= 2 * n - i - 1; j++) {
			int w = i + n;
			dp[w][j][0] = max(dp[w - 1][j][0], dp[w - 1][j + 1][0]) + a[w][j];
			dp[w][j][1] = max(max(dp[w - 1][j][1], dp[w - 1][j + 1][1]) + a[w][j], max(dp[w - 1][j][0], dp[w - 1][j + 1][0]) + row[w]);
		}
	for(int i = 1; i <= n; i++)
		ans = max(ans, dp[n * 2 - 1][i][1]);
	cout << ans;
	return 0;
}
  • 32
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值