http://acm.nyist.net/JudgeOnline/problem.php?pid=61
四维的DP ,但是用四维,肯定会超时。
从图中我们可以看到,在K 时刻,A 位于(i,ii ),B 位于(j,jj),那么在K -1 时刻 A 有两种状态,A 1 和A 2 ,B 有两种状态 B 1 和B 2 ,两两组合就有四种状态,所以K 时刻的最优解可由K -1 时刻四种状态的最优解加上,A 和 B 的值取得。
动态转移方程为:
dp[i][ii][j][jj] = max( dp[i][ii-1][j][jj-1] , dp[i][ii-1][j-1][jj] , dp[i-1][ii][j][jj-1] , dp[i-1][ii][j-1][jj] ) + map[i][ii] + map[j][jj];
所以我们可以直接枚举四个变量。但是要注意 A 和 B 点不能再同一点上。
但是无疑这种方法是超时的。四维的dp 数据量太大了
#include <stdio.h>
#include <string.h>
int dp[53][53][53][53];
int map[53][53];
int max(int a,int b)
{
return a>b? a:b;
}
int main()
{
int T,row,col,i,j,ii,jj,k,t1,t2,ans;
scanf("%d",&T);
do
{
scanf("%d%d",&row,&col);
for(i = 1 ; i <= row ; ++i)
for(j = 1 ; j <= col ; ++j)
scanf("%d",&map[i][j]);
for(i = 1 ; i <=row ; ++i)
for(j = 1 ; j <= row ; ++j)
for(ii = 1 ; ii <= col ; ++ii)
for(jj = 1 ; jj <= col ; ++jj)
if(i != j || ii != jj)
{
t1 = max(dp[i][ii-1][j][jj-1],dp[i][ii-1][j-1][jj]);
t2 = max(dp[i-1][ii][j][jj-1],dp[i-1][ii][j-1][jj]);
dp[i][ii][j][jj] = max(t1,t2) + map[i][ii] + map[j][jj];
}
ans = max(dp[row][col-1][row-1][col],dp[row-1][col][row][col-1]);
printf("%d\n",ans);
}while(--T);
// system("pause");
return 0;
}
i + ii - 1 明显是等于 i - 1 + ii 的,所以,我们标记一个点的时候只要一个步数和一个横坐标就行了。这样就把四维的降到了三位。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[110][110][110];
int map[55][55];
int main()
{
int N,n,m,i,j,ii,jj,k,s,t,all;
cin>>N;
while(N--)
{
memset(dp,0,sizeof(dp));
memset(map,0,sizeof(map));
cin>>m>>n;
for(i = 1; i <= m; i++)
for(j = 1; j <= n; j++)
{
cin>>map[i][j];
}
all = m+n;
for(k = 2; k <= all; k++)
for(i = 1; i <= m; i++)
for(j = 1; j <= m; j++)
{
if(i != j && i <= k && j <=k)
{
s = max(dp[k-1][i-1][j],dp[k-1][i-1][j-1]);
t = max(dp[k-1][i][j],dp[k-1][i][j-1]);
dp[k][i][j] = max(s,t) + map[i][k-i] + map[j][k-j];
}
}
int ans = max(dp[all-1][m][m-1] , dp[all-1][m-1][m]);
cout<<ans<<endl;
}
return 0;
}
还有一题与之非常相似。
http://ayit.acmclub.com/index.php?app=problem_title&id=233&problem_id=21491
知识A 点 和B 点能到达同一点。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[110][110][110],map[55][55];
int main()
{
int n,m,s,t,i,j,k;
cin>>m>>n;
for(i = 1; i <= m; i++)
for(j = 1; j <= n; j++)
cin>>map[i][j];
int all = m+ n;
for(k = 2; k <= all; k++)
for(i = 1; i <= m; i++)
for(j = 1; j <= m; j++)
if(i != j && i <= k && j <= k)
{
s = max(dp[k-1][i][j-1],dp[k-1][i-1][j]);
t = max(dp[k-1][i][j],dp[k-1][i-1][j-1]);
dp[k][i][j] = max(s,t) + map[i][k-i] + map[j][k-j];
}
int ans = max(dp[all-1][m][m-1],dp[all-1][m-1][m]);
cout<<ans<<endl;
return 0;
}