哈尔滨工程大学第十四届程序设计竞赛 (补题

F 小帆帆走迷宫(简单dp)

 一道其实不是很难的四维dp  但是在考场上因为只记录转弯次数没记录方向没写出来

看题发现 其实这道题就是二维数塔+转向费的dp

所以我们用dp[n][n][k][m]来记录状态 前两维n n 代表当前坐标 k记录转弯几次 m记录方向 当m=0 记没改变方向 当m=1 为改变了方向

因为要用到矩阵边界 所以我们要预处理 m为0时的价值 具体看代码

解法1

#include <stdio.h>
#include <iostream>
#include <string.h>
#define INF 0x3f3f3f3f
using namespace std;
int T,n;
int a[105][105];
int dp[105][105][20][2];
int main(int argc, char const *argv[])
{
	ios::sync_with_stdio(false);
	cin >> T;
	while(T--){
		cin >> n;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				cin >> a[i][j];
				 //memset(dp[i][j],INF,sizeof(dp[i][j]));
			}
		}
		memset(dp,INF,sizeof(dp));
		dp[1][1][0][0]=a[1][1];
		dp[1][1][0][1]=a[1][1];
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(i>1)
					for(int k=0;k<=19;k++){
						dp[i][j][k][0]=dp[i-1][j][k][0]+a[i][j];
						
					}
				if(j>1)
					for(int k=0;k<=19;k++){
						dp[i][j][k][1]=dp[i][j-1][k][1]+a[i][j];
					}
				for(int k=1;k<=18;k++){
					dp[i][j][k][1]=min(dp[i][j][k][1],dp[i][j][k-1][0]+(1<<(k-1)));
					dp[i][j][k][0]=min(dp[i][j][k][0],dp[i][j][k-1][1]+(1<<(k-1)));
				}
			}
		}
		int minn=INF;
		for(int a=0;a<=1;a++)
		for(int i=0;i<=18;i++){
			minn=min(minn,dp[n][n][i][a]);
		}
		cout<<minn<<'\n';
	}
	return 0;
}

  解法2 其实思路差不多 但是这个dp更容易理解

#include <stdio.h>
#include <iostream>
#include <string.h>
#define INF 0x3f3f3f3f
using namespace std;
int T,n;
int a[105][105];
int dp[105][105][20][2];
int main(int argc, char const *argv[])
{
	ios::sync_with_stdio(false);
	cin >> T;
	while(T--){
		cin >> n;
		memset(dp,INF,sizeof(dp));
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				cin >> a[i][j];
				 //memset(dp[i][j],INF,sizeof(dp[i][j]));
			}
		}
		dp[0][1][0][0]=0;
		dp[1][0][0][1]=0;
		for(int i=1;i<=n;i++){
			dp[1][i][0][1]=dp[1][i-1][0][1]+a[1][i];
			dp[i][1][0][0]=dp[i-1][1][0][0]+a[i][1];
		}
		for(int i=2;i<=n;i++){
			for(int j=2;j<=n;j++){
				for(int k=1;k<=18;k++){
				//	printf("%d\n",dp[i][j][k][0]);
					dp[i][j][k][1]=min(dp[i][j-1][k][1],dp[i][j-1][k-1][0]+(1<<(k-1)))+a[i][j];
					dp[i][j][k][0]=min(dp[i-1][j][k][0],dp[i-1][j][k-1][1]+(1<<(k-1)))+a[i][j];
				}
			}
		}
		int minn=INF;
		for(int a=0;a<=1;a++)
		for(int i=0;i<=18;i++){
			minn=min(minn,dp[n][n][i][a]);
		//	printf("%d\n",dp[n][n][i][a]);
		}
		cout<<minn<<'\n';
	}
	return 0;
}

  

posted @ 2019-04-21 20:12  Rain_day  阅读(223)  评论(1编辑  收藏  举报