同时取数求最值

同时取数求最大问题

方格取数

设有 N×N 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。某人从图中的左上角 A 出发,可以向下行走,也可以向右行走,直到到达右下角的 B 点。
在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从 A 点到 B 点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。

输入格式
第一行为一个整数N,表示 N×N 的方格图。
接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。
行和列编号从 1 开始。
一行“0 0 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

解释

dp[k][i1][i2]表示第K步时,分别从(1,1)(1,1)到(i1,k-i1),(i2,k-i2)的上的路径上和的集合。需要特别考虑的是,两条路线的重合情况。即i1i2,j1j2.当步数相同时。若i1==i2,即认为两者重合。重合的话,只加value[i1][i2]即可。

因为表示的是同时走的状况。
dp[k][i1][i2]的前一步有四种情况

  • i1向下,i2向下
  • (1,1)-->...-->dp[i1-1][j1]
  • (1,1)-->...-->dp[i2-1][j1]
  • i1向下,i2向右
  • (1,1)-->...-->dp[i1-1][j1]
  • (1,1)-->...-->dp[i2][ji-1];
  • i1向右,i2向下
  • i1向右,i2向右
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
int value[15][15];
int dp[30][15][15];
// dp[步数][i1行数][i2行数]

int main()
{
    int n;
    cin>>n;
    int c,r,v;
    while(cin>>r>>c>>v,c||r||v) value[r][c]=v;
    for(int k=2;k<=n*2;k++){
        for(int i1=1;i1<=n;i1++){
            for(int i2=1;i2<=n;i2++){
                int j1=k-i1;
                int j2=k-i2;
                //判断越界
                if(j1>=1&&j1<=n&&j2>=1&&j2<=n){
                    int num=value[i1][j1];
                    //判断是否重合
                    if(i1!=i2){
                        num+=value[i2][j2];
                    }
                    int &x=dp[k][i1][i2];
                    //下下
                    x=max(x,dp[k-1][i1-1][i2-1]+num);
                    //下右
                    x=max(x,dp[k-1][i1-1][i2]+num);
                    //右下
                    x=max(x,dp[k-1][i1][i2-1]+num);
                    //右右
                    x=max(x,dp[k-1][i1][i2]+num);
                }
            }
        }
    }
    cout<<dp[n*2][n][n];
    return 0;
}

传纸条

第一行有 2 个用空格隔开的整数 m 和 n,表示学生矩阵有 m 行 n 列。
接下来的 m 行是一个 m×n 的矩阵,矩阵中第 i 行 j 列的整数表示坐在第 i 行 j 列的学生的好心程度,每行的 n 个整数之间用空格隔开。
输出格式
输出一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。

3 3
0 3 9
2 8 5
5 7 0
#include<bits/stdc++.h>
using namespace std;

int m,n;
int value[60][60];
int dp[120][60][60];

int main()
{
    cin>>m>>n;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            cin>>value[i][j];
    for(int k=2;k<=m+n;k++){
        for(int i1=1;i1<=m;i1++){
            for(int i2=1;i2<=m;i2++){
                int j1=k-i1;
                int j2=k-i2;
                if(j1>=1&&j1<=n&&j2>=1&&j2<=n){
                    int num=value[i1][j1];
                    if(i1!=i2){
                        num+=value[i2][j2];
                    }
                    int &x=dp[k][i1][i2];
                    x=max(x,dp[k-1][i1-1][i2-1]+num);
                    x=max(x,dp[k-1][i1-1][i2]+num);
                    x=max(x,dp[k-1][i1][i2-1]+num);
                    x=max(x,dp[k-1][i1][i2]+num);
                }
            }
        }
    }
    cout<<dp[n+m][m][m];
    return 0;
}
posted @ 2022-10-26 17:10  认真游泳的鱼  阅读(20)  评论(0)    收藏  举报