收集样本问题

方法一

/**
思路:
从起点到终点找到两条最优的路线,且不能重复,用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];
            }
    /**因为不可能走到同一个点,所以最多走2n-1步**/
    printf("%d\n",dp[2*n-1][n][n-1]);

    //cout << sampleSelect(n)<< endl;
    return 0;
}
/*
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 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;
}

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值