• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
HaibaraAi
博客园    首页    新随笔    联系   管理    订阅  订阅

codeforces.com/problemset/problem/213/C

虽然一开始就觉得从右下角左上角直接dp2次是不行的,后面还是这么写了WA了
两次最大的并不一定是最大的,这个虽然一眼就能看出,第一次可能会影响第二次让第二次太小。
这是原因。
5
4 32 1 18 41
47 38 7 43 43
48 23 39 40 23
26 39 33 5 36
31 29 7 26 47
这组数据是结果。
走完第一遍成
0 32 1 18 41
0 38 7 43 43
0 0 0 0 0
26 39 33 5 0
31 29 7 26 0
这样倒着走回去一定会经过0导致第二遍小很多。
正确走法
5
0 32 1 18 41
0 38 7 43 43
0 23 39 40 23
0 0 0 5 36
31 29 0 0 0
然后
5
0 0 1 18 41
0 0 7 43 43
0 0 0 0 0
0 0 0 5 0
31 29 0 0 0
这样和为508比两次取最大的482还大。
完全想不到怎么弄了。上一次求两次和最短路的走过了后就不能走,也想成两次跑最小,也是跪,结果应该用最小费用流。

这个也是没发现,不管怎么走一定每次确定步数后都会在同一条对角线上。
所以可以一条对角线一条一条的推。然而要同时确定两条路,走过去再走回来就等于走过去两条路,经过同一个点的时候只取一次。
dp[d][i][j]表示到第d条对角线时第一条路在i行,第二条路在j行最大的和能取多大,一路推到最后,这里可以用滚动数组dp内存就只有n*n了。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 305;
const ll mod = 1e9 + 7;
const double eps = 1e-12;
int a[N][N];
int dp[2][N][N];
int main() {
	int n;cin >> n;
	for (int i = 1;i <= n;i++)
		for (int j = 1;j <= n;j++)
			cin >> a[i][j];
	memset(dp, -2, sizeof dp);
	dp[1][1][1] = a[1][1];
	int now = 1;
	for (int d = 2;d < n + n;d++) {
		now ^= 1;
		for (int i = max(1,d-n+1);i <= min(n,d);i++)
			for (int j = max(1,d-n+1);j <= min(n,d);j++) {
				for (int x = i - 1;x <= i;x++) {
					for (int y = j - 1;y <= j;y++) {
						if (x >= max(1, d - n) && x <= min(n, d - 1) && y >= max(1,d - n) && y <= min(n, d - 1)) {
							int val = a[i][d - i + 1] + a[j][d - j + 1];
							if (i == j)val /= 2;
							dp[now][i][j] = max(dp[now][i][j], dp[now ^ 1][x][y] + val);
						}
					}
				}
			}
		for (int i = 0;i <= n;i++)
			for (int j = 0;j <= n;j++)dp[now ^ 1][i][j] = -1000000000;
	}
	cout << dp[now][n][n];
	return 0;
}
posted @ 2015-06-12 21:32  HaibaraAi  阅读(216)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3