1. 程式人生 > >CodeForces - 429B Working out(dp)

CodeForces - 429B Working out(dp)

題目連結

看到題目,沒什麼思路

看了大佬部落格:https://blog.csdn.net/xiaolonggezte/article/details/69145427,豁然開朗,還是有些小問題沒注意,wa了挺久

題意:

    在n*m的格子裡,A從(1,1)到(n,m),B從(n,1)到(1,m),

    A只能從 (i, j) 到 (i+1 , j) 或者 (i, j+1),B只能從 (i, j) 到 (i-1, j) 或者 (i, j+1)

    A和B的路線有且只有一點重合,並且這一點不在A和B的起點或終點,

    求怎樣走使A和B的路線的權值之和(重合點的權值不計算)最大

思路:

    把路線分成四段,設重合點為x,計算 (1,1)到x,(n,m)到x,(1,m)到x,(n,1)到x 四段路的權值和;

注意:

    重合的點不在邊界,並且只有一個點重合!

 

#include <iostream> 
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

ll dp1[1100][1100],dp2[1100][1100],dp3[1100][1100],dp4[1100][1100];
//重合的點為x,dp1:(1,1)到x,dp2:(n,m)到x,dp3:(n,1)到x,dp4: (1,m)到x
ll a[1100][1100];

int main()
{
	memset(dp1,0,sizeof(dp1));
	memset(dp2,0,sizeof(dp2));
	memset(dp3,0,sizeof(dp3));
	memset(dp4,0,sizeof(dp4));
    int n,m;
	cin>>n>>m;
    for(int i = 1;i <= n;i++)
	    for(int j = 1;j <= m;j++)
		    cin>>a[i][j];
		    
	for(int i = 1;i <= n;i++)
	    for(int j = 1;j <= m;j++)
		    dp1[i][j] = max(dp1[i-1][j],dp1[i][j-1])+a[i][j];
	for(int i = n;i > 0;i--)
	    for(int j = m;j > 0;j--)
		    dp2[i][j] = max(dp2[i+1][j],dp2[i][j+1])+a[i][j];
	for(int i = n;i > 0;i--)
	    for(int j = 1;j <= m;j++)
		    dp3[i][j] = max(dp3[i+1][j],dp3[i][j-1])+a[i][j];
	for(int i = 1;i <= n;i++)
	    for(int j = m;j > 0;j--)
		    dp4[i][j] = max(dp4[i-1][j],dp4[i][j+1])+a[i][j];

    ll ans = 0;
    //注意(i,j)不在邊界 
    for(int i  = 2; i < n; i ++)
        for(int j = 2; j < m; j ++)
        {
        	//除了(i,j)外的點不能再重合,所以一共就兩種走法 ,沒考慮路徑,直接用和-4*a[i][j],wa瘋 
            ans = max(ans,dp1[i - 1][j] + dp2[i + 1][j]+dp3[i][j - 1] + dp4[i][j + 1]);
            ans = max(ans,dp1[i][j - 1] + dp2[i][j + 1] + dp3[i + 1][j] + dp4[i - 1][j]);
        }
	cout<<ans<<endl;        					 
	return 0;
}