CodeForces - 1517D D. Explorer Space(dp)
题意:
给出一个 n ⋅ m n \cdot m n⋅m 的网格和每条边的边权,求从每个点出发,走 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[i−1][j][k−1]+w1,dp[i+1][j][k−1]+w2,dp[i][j−1][k−1]+w3,dp[i][j+1][k−1]+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;
}
}

浙公网安备 33010602011771号