CodeForces - 1517D Explorer Space(dp)

题目链接:点击查看

题目大意:给出一个 n ∗ m n*m nm 的矩阵,每个点都可以到达相邻的四个点,每条边都有一个边权,问对于每个点 ( i , j ) (i,j) (i,j),走 k k k 步可以回到 ( i , j ) (i,j) (i,j) 的最短路径

题目分析:首先不难看出 k k k 如果是奇数的话无解,然后可以将题目转换为:从 ( i , j ) (i,j) (i,j) k 2 \frac{k}{2} 2k 步可以到达的最短路径,不难看出用后 k 2 \frac{k}{2} 2k 步沿着前面的路径原路返回这样一定是最优的

第一反应是暴力每个点,就是对于每个点 ( x , y ) (x,y) (x,y) 来说单独思考, d p i , j , k dp_{i,j,k} dpi,j,k 代表从点 ( x , y ) (x,y) (x,y) 出发走了 k k k 步到达点 ( i , j ) (i,j) (i,j) 的最短路径,这样思考正确性毋庸置疑,就是时间复杂度有点大: O ( n ∗ m ∗ k 2 ∗ k 2 ∗ k 2 ∗ 4 ) O(n*m*\frac{k}{2}*\frac{k}{2}*\frac{k}{2}*4) O(nm2k2k2k4),三个 k 2 \frac{k}{2} 2k 分别代表需要转移的矩形的长和宽,以及需要迭代的次数, 4 4 4 代表的是每次需要向四个方向转移

后来发现,我们并不需要关注起点在哪,只需要关注走了 k 2 \frac{k}{2} 2k 步之后到达 ( x , y ) (x,y) (x,y) 的最小路径是多少就行,直接乘以 2 2 2 就是我们需要的答案了

所以直接迭代 k 2 \frac{k}{2} 2k 次,更新每个点的状态即可,时间复杂度 O ( n ∗ m ∗ k 2 ) O(n*m*\frac{k}{2}) O(nm2k)

最后提一句,第一种方法卡卡常是可以过的,因为看到了前排大佬和我思路一样,但我却给写T了,代码放在后面,主要是展示思路

代码:
AC代码

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
     
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){
     if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
     
	if(x<0){
     x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=510;
const int b[4][2]={
     0,1,0,-1,1,0,-1,0};
int n,m,k;
int raw[N][N],col[N][N];//raw[i][j]:(i,j)->(i,j+1) col[i][j]:(i,j)->(i+1,j)
int dp[N][N][11];
int main()
{
     
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	read(n),read(m),read(k);
	for(int i=1;i<=n;i++) {
     
		for(int j=1;j<m;j++) {
     
			read(raw[i][j]);
		}
	}
	for(int i=1;i<n;i++) {
     
		for(int j=1;j<=m;j++) {
     
			read(col[i][j]);
		}
	}
	if(k&1) {
     
		for(int i=1;i<=n;i++) {
     
			for(int j=1;j<=m;j++) {
     
				printf("-1 ");
			}
			puts("");
		}
		return 0;
	}
	k/=2;
	for(int t=1;t<=k;t++) {
     
		for(int i=1;i<=n;i++) {
     
			for(int j=1;j<=m;j++) {
     
				dp[i][j][t]=inf;
				for(int p=0;p<4;p++) {
     
					int xx=i+b[p][0];
					int yy=j+b[p][1];
					if(xx<=0||xx>n||yy<=0||yy>m) {
     
						continue;
					}
					int w;
					if(p==0) {
     
						w=raw[i][j];
					} else if(p==1) {
     
						w=raw[xx][yy];
					} else if(p==2) {
     
						w=col[i][j];
					} else if(p==3) {
     
						w=col[xx][yy];
					}
					dp[i][j][t]=min(dp[i][j][t],dp[xx][yy][t-1]+w*2);
				}
			}
		}
	}
	for(int i=1;i<=n;i++) {
     
		for(int j=1;j<=m;j++) {
     
			printf("%d ",dp[i][j][k]);
		}
		puts("");
	}
    return 0;
}

TLE代码:

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
     
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){
     if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
     
	if(x<0){
     x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=510;
const int b[4][2]={
     0,1,0,-1,1,0,-1,0};
int n,m,k;
int raw[N][N],col[N][N];//raw[i][j]:(i,j)->(i,j+1) col[i][j]:(i,j)->(i+1,j)
int dp[N][N][11];
struct Node {
     
	int x,y,step;
};
int solve(int x,int y,int k) {
     
	for(int t=0;t<=k;t++) {
     
		for(int i=max(x-t,1);i<=min(x+t,n);i++) {
     
			int d=t-abs(i-x);
			for(int j=max(y-d,1);j<=min(y+d,m);j++) {
     
				dp[i][j][t]=inf;
			}
		}
	}
	dp[x][y][0]=0;
	for(int t=1;t<=k;t++) {
     
		for(int i=max(x-t,1);i<=min(x+t,n);i++) {
     
			int d=t-abs(i-x);
			for(int j=max(y-d,1);j<=min(y+d,m);j++) {
     
				for(int p=0;p<4;p++) {
     
					int xx=i+b[p][0];
					int yy=j+b[p][1];
					if(xx<=0||xx>n||yy<=0||yy>m) {
     
						continue;
					}
					if(abs(xx-x)+abs(yy-y)>t-1) {
     
						continue;
					}
					int w;
					if(p==0) {
     
						w=raw[i][j];
					} else if(p==1) {
     
						w=raw[xx][yy];
					} else if(p==2) {
     
						w=col[i][j];
					} else if(p==3) {
     
						w=col[xx][yy];
					}
					dp[i][j][t]=min(dp[i][j][t],dp[xx][yy][t-1]+w);
				}
			}
		}
	}
	int ans=inf;
	for(int i=max(x-k,1);i<=min(x+k,n);i++) {
     
		int d=k-abs(i-x);
		for(int j=max(y-d,1);j<=min(y+d,m);j++) {
     
			ans=min(ans,dp[i][j][k]);
		}
	}
	return ans*2;
}
int main()
{
     
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	read(n),read(m),read(k);
	for(int i=1;i<=n;i++) {
     
		for(int j=1;j<m;j++) {
     
			read(raw[i][j]);
		}
	}
	for(int i=1;i<n;i++) {
     
		for(int j=1;j<=m;j++) {
     
			read(col[i][j]);
		}
	}
	if(k&1) {
     
		for(int i=1;i<=n;i++) {
     
			for(int j=1;j<=m;j++) {
     
				printf("-1 ");
			}
			puts("");
		}
		return 0;
	}
	for(int i=1;i<=n;i++) {
     
		for(int j=1;j<=m;j++) {
     
			printf("%d ",solve(i,j,k/2));
		}
		puts("");
	}
    return 0;
}

你可能感兴趣的:(动态规划,CodeForces上分)