Algorithm training grid access (dual thread DP, Blue Bridge Cup C++)

Test question algorithm training grid access

Resource limit
Time limit: 1.0s Memory limit: 256.0MB
Problem description
  There is a grid graph of



N N (N<=10), we fill some of the squares with positive integers, and other squares. Put in the number 0.   Someone starts from point A (1,1) in the upper left corner of the figure, and can walk down or to the right until he reaches point B (N,N) in the lower right corner. On the way he walks, he can take the number in the square (the square after taking it will become the number 0).   This person walks twice from point A to point B. Try to find two such paths so that the sum of the obtained numbers is the largest. Input format   The first line of input is an integer N (representing a grid of N N), and each subsequent line has three integers. The first two indicate the position, and the third number is the number placed at that position. A single line of 0 indicates the end of input.
Output format
  only needs to output an integer, which represents the maximum sum obtained on the two paths.
Sample input
  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
Sample output
  67

Foreword: Yesterday I wrote a blog about single-threaded dp questions, and today we ushered in the top hardware dual-threaded dp. At the beginning, I just wanted to use recursion to figure out whether it could be done. I thought it was relatively simple. I knew I opened debug. Later, I learned that this can only get a local optimal solution, not a global optimal solution (the result of the first walk is not a big problem, but when you walk the second time, there will be many 0s, which leads to results in many cases. It will go wrong, that is, you did not go the right way), if you want to use the recursive thinking that is to pass the coordinates as the actual parameters, there will be wrong judgments.

/这个是我最开始错误的思路:递归做法!事实证明不能得出结果 !!
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include<string.h>

using namespace std;
int ans = 0;
int cot = 0;
void func(int a[][10] , int x,int y,int n)
{
    
    
    int i = x,j = y,k;
    ans += a[i][j];
    a[i][j] = 0;
    if(x == n && y ==n)
    {
    
    
        cot++;
        if(cot != 2)
        {
    
    
            func(a,1,1,n);
        }
        else
        {
    
    
            cout << ans << endl;
            return;
        }
    }
    if(x == n)
    {
    
    
        func(a,i,j+1,n);
    }
    if(y == n)
    {
    
    
        func(a,i+1,j,n);
    }
    a[i+1][j]>a[i][j+1] ? func(a,i+1,j,n) : func(a,i,j+1,n);
}

int main( )
{
    
    
	int n,i,j,k;
	cin >> n;
	int a[10][10];
	memset(a,0,sizeof(a));
	while(i||j||k)
    {
    
    
        cin >> i >> j >> k;
        a[i][j] = k;
    }
    func(a,1,1,n);
	return 0;
}

Ideas and analysis:

1. Since it is a multi-threaded dynamic programming, then we don’t need to consider how to take each step, but how to get the result of each step, that is, just consider how much the weight of each step is , and take what can be obtained at each step The maximum weight is added together, so we can think of this problem as two people walking from (1,1) to (n,n) at the same time, but it should be noted that when two people go to the same coordinate at some time, the weight is only Can be added once!
2. First, we need to use a four-dimensional array dp[21][21][21][21] to record the sum of weights;
dp[i][j][k][l] where i represents the first human x coordinate, j represents the column coordinate of the first person, k is the second person abscissa, l represents the column coordinate of the second person
3, then we need to list a dynamic transfer equation , per home in order to A regular equation for one-step weights. The idea of ​​deriving the equation is: walking to this coordinate can only come from the left or above this coordinate , and each time you take the largest of each person from the left or the right Value , and then take the largest one from these two maximum values . These two coordinates are used as the path selection, and then the weights of the respective coordinates of the two people are added; so it is not difficult for us to derive the code:

dp[i][j][k][l]=max(max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]),max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]))+a[i][j]+a[k][l];

※But we just mentioned the situation when two people walk to the same coordinate:

If it is reached, the current weight will be subtracted once

 if(i==k && l==j)		//i,j与k,l相同
 {
    
    
      dp[i][j][k][l]-=a[i][j]; //-=[k][l]也一样咯
 }

At the end of the loop to (n,n,n,n), the weights have been added and the result can be printed:

	cout<<dp[n][n][n][n]<<endl;	

Finally, attach the complete code:

#include <stdio.h>
#include <iostream>
using namespace std;

int main()
{
    
    

	int dp[21][21][21][21],a[21][21],n,x,y,z;
	int i,j,k,l;
	cin>>n>>x>>y>>z;
	while(x||y||z)
	{
    
    
		a[x][y]=z;      //给数组赋值
		cin>>x>>y>>z;
	}
	for(i=1;i<=n;i++)   //第一个人从左或者上来,坐标都是从(1,1)开始所以循环从1开始
	{
    
    
		for(j=1;j<=n;j++)
		{
    
    
			for(k=1;k<=n;k++)   //第二个人也是从左或者上来
			{
    
    
				for(l=1;l<=n;l++)
				{
    
    
					dp[i][j][k][l]=max(max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]),max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]))+a[i][j]+a[k][l];
                    if(i==k&&l==j)  //i,j与k,l相同,就减去一个人的权值
					{
    
    
                    	dp[i][j][k][l]-=a[i][j];
                    }
				}
			}
		}
	}
	cout<<dp[n][n][n][n]<<endl;
	return 0;
}

Afterword: I saw the new dp question type on a whim in the middle of the night or finished writing this blog. I just got free from dfs and bfs. Not only did I regret why I didn’t bring the data structure book back, but it seemed that I would need to study it again in a week. Algorithm is already written, and there may be some errors in writing faster. If you have any insights on this question or make mistakes, please communicate more!

Guess you like

Origin blog.csdn.net/Kyrie_irving_kun/article/details/113623456