方法一
/**
思路:
从起点到终点找到两条最优的路线,且不能重复,用DP思想的话可以通过四维数组来实现
设dp[x1][y1][x2][y2]表示从起点(1,1)开始到点(x1,y1)(x2,y2)的最优路线,则它上一步有四种状态:
1.第一个点从上走来,第二个点也从上走来,则此时好感度为dp[x1-1][y1][x2-1][y2]+mp[x1][y1]+mp[x2][y2]
2.第一个点从左走来,第二个点也从左走来,则此时好感度为dp[x1][y1-1][x2][y2-1]+mp[x1][y1]+mp[x2][y2]
3.第一个点从上走来,第二个点从左走来,此时好感度为dp[x1-1][y1][x2][y2-1]+mp[x1][y1]+mp[x2][y2]
4.第一个点从左走来,第二个点从上走来,此时好感度为dp[x1][y1-1][x2-1][y2]+mp[x1][y1]+mp[x2][y2]
取四种情况中最大的即可
但是四重循环的话很有可能会超时,所以我们需要优化一下
因为两个人是同时走,所以x1+y1=x2+y2=k,因此我们可以用k来表示当前走的步数
状态转移方程为:
dp[k][x1][x2]=max(max(dp[k-1][x1][x2],dp[k-1][x1-1][x2-1]),max(dp[k-1][x1-1][x2],dp[k-1][x1][x2-1]))+mp[x1][k-x1]+mp[x2][k-x2];
**/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[110][55][55],p[55][55];
int main()
{
int n,a,b,c;
cin>>n;
memset(dp,0,sizeof(dp));
memset(p,0,sizeof(p));
while(true)
{
cin>>a>>b>>c;
if(!a&&!b&&!c)
break;
p[a][b]=c;
}
dp[1][1][1]=p[1][1];
for(int k=2; k<=2*n; ++k)
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
{
int y1=k-i;
int y2=k-j;
if(y1>n||y2>n||y1<=0||y2<=0||i<=j)
continue;
dp[k][i][j]=max(max(dp[k-1][i][j],dp[k-1][i-1][j-1]),
max(dp[k-1][i-1][j],dp[k-1][i][j-1]))+p[i][y1]+p[j][y2];
}
printf("%d\n",dp[2*n-1][n][n-1]);
return 0;
}
方法二
方2
题目描述:机器人R在一个有n×n个方格区域F中收集样本。(i,j)方格中样本的
价值为v(i,j),如图所示,R从方形区域F的左上角A点出发,向下或向右行走,直到右
下角的B点,在走过的路上,收集方格中的样本。R从A点到B点共走2次,试找出R的
2条行走路径,使其取得的样本总价值最大。
二、题目分析
性质1:机器人R从A点走到B点的一条路径的方格数为2*n-1
证明:A点的坐标是(1,1),B点的坐标是B(n, n),
从A点走到B点,按照向下或向右行走的规则,
则A必须向下和向左各跨n-1个方格,
再加上原来在起点(1,1)的那个方格,
所以A点走到B点的一条路径的方格数为 2*(n-1)+1=2*n-1;
性质2:记机器人R的当前坐标是N(X,Y),从起点A到当前点N的路径方格数是steps,
则有steps = x+y—1
证明:因为A、N的坐标分别为(1,1)和(X,Y),
所以从起点A到N
向下走的步数和是X-1
向右走的步数和是Y-1,
再加上原来在起点(1,1)的那个方格,
则从起点A到当前点N的路径方格数为: X-1+Y-1+1=X+Y-1
三、题目解答
此题可用动态规划解答,机器人走的步数将问题划分为2*n-1个状态.
题目要求R从A到B共走两次,如果分两次来走的话,
一个就是效率低下问题,
另一个就是难以标记那些点是
在第一次已经走过,对重复走两次的点所造成的误差难以消除。
有个办法就是同时走两条路径,当两条路径走到相同一点时,只对相同点取值一次。
由性质2我们知道,在一定的Steps的情况下,
如果知道当前点的X轴坐标,
就可以知道Y轴坐标Y=Steps—X+1,
所以可以记dp[Steps][x1][x2]为两条路径同时走Steps步的情况下,
到达(x1,y1)(x2,y2)所取的当前最大值。
由于机器人只能向下和向左走,那么在(x1,y1)(x2,y2)的
前一个状态就是一下四种之一:
(x1,y1-1)(x2,y2-1);
(x1,y1-1)(x2-1,y2);
(x1-1,y1)(x2-1,y2)
(x1-1,y1)(x2,y2-1)
当(x1,y1)(x2,y2)是不同点的情况下,状态转移方程如下:
dp[Steps][x1][x2]=max{
dp[steps-1][x1][x2]+mp[x1][y1]+mp[x2][y2],
dp[steps-1][x1][x2-1]+mp[x1][y1]+mp[x2][y2],
dp[steps-1][x1-1][x2]+mp[x1][y1]+mp[x2][y2],
dp[steps-1][x1-1][x2-1]+mp[x1][y1]+mp[x2][y2]
}
当(x1,y1)(x2,y2)是相同点的情况下,状态转移方程如下:
dp[steps][x1][x2] = max{
dp[steps-1][x1][x2]+mp[x1][y1],
dp[steps-1][x1][x2-1]+mp[x1][y1],
dp[steps-1][x1-1][x2]+mp[x1][y1],
dp[steps-1][x1-1][x2-1]+mp[x1][y1]
}
**/
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int dp[110][55][55];
int mp[55][55];
void MaxValue(int steps,int x1,int x2,int &value)
{
int y1=steps+1-x1;
int y2=steps+1-x2;
if(x1==x2)
value = max(dp[steps][x1][x2]+mp[x1][y1],value);
else
value = max(dp[steps][x1][x2]+mp[x1][y1]+mp[x2][y2],value);
}
int main()
{
int n,a,b,c;
cin>>n;
memset(dp,0,sizeof(dp));
memset(mp,0,sizeof(mp));
while(true)
{
cin>>a>>b>>c;
if(!a&&!b&&!c)
break;
mp[a][b]=c;
}
dp[1][1][1]=mp[1][1];
int value;
for(int steps=2;steps<=2*n-1;steps++) {
for(int x1=1;x1<=steps;x1++) {
for(int x2=1;x2<=steps;x2++) {
value=0;
MaxValue(steps-1,x1,x2,value);
MaxValue(steps-1,x1,x2-1,value);
MaxValue(steps-1,x1-1,x2,value);
MaxValue(steps-1,x1-1,x2-1,value);
dp[steps][x1][x2]=value;
}
}
}
cout<<dp[2*n-1][n][n]<<endl;
return 0;
}