https://www.luogu.com.cn/problem/P1004
错误示例:跑两遍dp
#include<bits/stdc++.h>
using namespace std;
// clock_t start, end;
// start = clock();
// end = clock();
// cout << (double) (end - start) / CLOCKS_PER_SEC << endl;
//ios::sync_with_stdio(false);
//cin.tie(nullptr);
#define int long long
#define lowbit(x) (x&-x)
#define ispow(n) (n & (n - 1)) == 0 //O(1) 判断是否是 2^k(2的k次方)
#define rep(i, x, y) for(int i=(x);i<=(y);++i)
#define dep(i, x, y) for(int i=(x);i>=(y);--i)
#define gcd(a, b) __gcd(a,b)
const long long mod = 1e9 + 7;
const int maxn = 1e3 + 10;
int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int n;
int dp[200][200];
int a[200][200];
pair<int,int> pp[200][200];
void solve(){
for(int i =1;i<=n;i++) {
for (int j = 1; j <= n; j++) {
if(dp[i - 1][j]>=dp[i][j - 1]&& i>1) {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + a[i][j];
pp[i][j].first = i - 1,pp[i][j].second = j;
}
else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + a[i][j];
pp[i][j].first = i, pp[i][j].second = j - 1;
}
}
}
}
void path(int x, int y)
{
a[x][y] = 0;
if(x == 1&& y == 1)
{
return ;
}
path(pp[x][y].first,pp[x][y].second);
// cout<<x<<' '<<y<<endl;
}
signed main() {
cin>>n;
int x,y,z;
while(cin>>x>>y>>z&&x+y+z)
{
a[x][y] = z;
}
int ans =0;
solve();
ans += dp[n][n];
memset(dp,0,sizeof(dp));
path(n,n);
solve();
cout<< ans+dp[n][n]<<endl;
return 0;
}
显然,这样做有问题。
举个栗子:
0 2 5
2 6 0
0 6 0
用上面的程序跑出来会有问题。
思考,用四维矩阵,每一次走就有四种走法,就很容易的出转移方程了:
#include<bits/stdc++.h>
using namespace std;
// clock_t start, end;
// start = clock();
// end = clock();
// cout << (double) (end - start) / CLOCKS_PER_SEC << endl;
//ios::sync_with_stdio(false);
//cin.tie(nullptr);
#define int long long
#define lowbit(x) (x&-x)
#define ispow(n) (n & (n - 1)) == 0 //O(1) 判断是否是 2^k(2的k次方)
#define rep(i, x, y) for(int i=(x);i<=(y);++i)
#define dep(i, x, y) for(int i=(x);i>=(y);--i)
#define gcd(a, b) __gcd(a,b)
const long long mod = 1e9 + 7;
const int maxn = 1e3 + 10;
int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int n;
int dp[20][20][20][20];//第一个人走到 i,j 第二个人走到 k l的最优解
int a[200][200];
pair<int,int> pp[200][200];
signed main() {
cin>>n;
int x,y,z;
while(cin>>x>>y>>z&&x+y+z)
{
a[x][y] = z;
}
rep(i,1,n)
{
rep(j,1,n)
{
rep(k,1,n)
{
int l = i + j - k;
if(l < 0)break;
if(i == k&&j == l)
dp[i][j][k][l] =
max(max(dp[i - 1][j][k][l - 1], dp[i - 1][j][k - 1][l]), max(dp[i][j - 1][k - 1][l],
dp[i][j - 1][k][l - 1])) +a[i][j];
else
dp[i][j][k][l] = max(max(dp[i - 1][j][k][l - 1], dp[i - 1][j][k - 1][l]),max(dp[i][j - 1][k - 1][l],
dp[i][j - 1][k][l - 1]))+a[i][j] + a[k][l];
}
}
}
cout<<dp[n][n][n][n]<<endl;
return 0;
}