CodeForces - 1517D D. Explorer Space(dp)

题意:

给出一个 n ⋅ m n \cdot m nm 的网格和每条边的边权,求从每个点出发,走 k k k步回到起点的最短路。

题解:

如果 k k k为奇数,明显回不到起点,直接输出-1即可。

因为要回到起点,所以出去的路和回来的路是一样的,如果是不一样的,那么选择其中前段 k / 2 k/2 k/2和后段 k / 2 k/2 k/2 中小的一段来回走,此时边权和比之前会更优,所以我们只要求出出去的 k / 2 k/2 k/2,那么回来只需乘2即可。

那么怎么求出去的呢?设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示从点 ( i , j ) (i,j) (i,j) 出发走k步的最短路,那么转移方程就容易写了:

d p [ i ] [ j ] [ k ] = m i n ( d p [ i − 1 ] [ j ] [ k − 1 ] + w 1 , d p [ i + 1 ] [ j ] [ k − 1 ] + w 2 , d p [ i ] [ j − 1 ] [ k − 1 ] + w 3 , d p [ i ] [ j + 1 ] [ k − 1 ] + w 4 ) dp[i][j][k]=min(dp[i-1][j][k-1]+w_1,dp[i+1][j][k-1]+w_2,dp[i][j-1][k-1]+w_3,dp[i][j+1][k-1]+w_4) dp[i][j][k]=min(dp[i1][j][k1]+w1,dp[i+1][j][k1]+w2,dp[i][j1][k1]+w3,dp[i][j+1][k1]+w4)

最后答案就是 d p [ i ] [ j ] [ k / 2 ] ⋅ 2 dp[i][j][k/2] \cdot 2 dp[i][j][k/2]2

代码:

#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7; 
const int MAXN=25e4+5;
const int inf=0x3f3f3f3f;
ll dp[MAXN][22];
std::vector<pii> v[MAXN];
int cal(int m,int i,int j)
{
    return (i-1)*m+j;
}
int main()
{
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<m;j++)
        {
            int x;
            cin>>x;
            v[cal(m,i,j)].push_back(make_pair(cal(m,i,j+1),x));
            v[cal(m,i,j+1)].push_back(make_pair(cal(m,i,j),x));
        }
    }
    for(int i=1;i<=n-1;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int x;
            cin>>x;
            v[cal(m,i,j)].push_back(make_pair(cal(m,i+1,j),x));
            v[cal(m,i+1,j)].push_back(make_pair(cal(m,i,j),x));
        }
    }
    if(k&1)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                cout<<-1<<" ";
            }
            cout<<endl;
        }
        return 0;
    }
    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=n*m;i++) dp[i][0]=0;
    for(int i=1;i<=k/2;i++)
    {
        for(int j=1;j<=n*m;j++)
        {
            for(auto p:v[j])
            {
                
                dp[j][i]=min(dp[j][i],dp[p.first][i-1]+p.second);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cout<<dp[cal(m,i,j)][k/2]*2<<" ";
        }
        cout<<endl;
    }
}
posted @ 2021-05-07 20:10  TheBestQAQ  阅读(56)  评论(0)    收藏  举报