方格取数问题

算法一:前向后向深搜(只通过一个,其余超时)

#include<iostream>
#include<cstring>
using namespace std;
	
void dfsFront(int fx, int fy);							// 起点到终点前向深度搜索
void dfsBack(int bx, int by);							// 终点到起点后向深度搜索
bool moveFront(int fx, int fy, int i, int &nx, int &ny);// 下右移是否出界,并返回移动后的坐标	
bool moveBack(int bx, int by, int i, int &nx, int &ny);	// 上左移是否出界,并返回移动后的坐标

int n;
int a[11][11];											// 对数组进行周边扩充一圈0
int tmp = 0;											// 一次深搜的数值大小
int ans = 0;											// 各种深搜情况的最大值

int main(){
	cin >> n;
	memset(a, 0, sizeof(a));
	int i, j, v;
	cin >> i >> j >> v;
	while(i != 0 || j != 0 || v || 0){	
		a[i][j] = v;
		cin >> i >> j >> v;
	}		
	dfsFront(0, 0);
	cout << ans << endl;
	return 0;
}

void dfsFront(int fx, int fy){
	if(fx == n && fy == n){						        // 到了终点后,进入后向深度搜索
		dfsBack(fx, fy);
		return;
	}
	int nx, ny;
	for(int i = 0; i <= 1; i++){
		if(moveFront(fx, fy, i, nx, ny)){
			int k = a[nx][ny];							// 前向深搜到达该位置后,该位置数值变为0
			a[nx][ny] = 0;
			tmp += k;									// 计数累计增加
			dfsFront(nx, ny);	
			tmp -= k;									// 该位置向另一方向移动时要减去向上个方向移动时累加的数值
			a[nx][ny] = k;								// 并复原一个方向的位置的原始值
		}
	}
}
void dfsBack(int bx, int by){
	if(bx == 0 && by == 0){
		ans = max(ans, tmp);							// 一次完整深搜完成,比较得出最大的深搜结果
		return;			
	}
	int nx, ny;
	for(int i = 2; i <= 3; i++){
		if(moveBack(bx, by, i, nx, ny)){
			tmp += a[nx][ny];
			dfsBack(nx, ny);
			tmp -= a[nx][ny];
		}
	}
}

bool moveFront(int fx, int fy, int i, int &nx, int &ny){
	if(i == 0){											// 下移
		nx = fx + 1;									// 右移
		ny = fy;
	}else if(i == 1){
		nx = fx;
		ny = fy + 1;
	}
	if(nx < 0 || nx > n || ny < 0 || ny > n){			// 越界
		return false;
	}else{
		return true;	
	}

}
bool moveBack(int bx, int by, int i, int &nx, int &ny){
	if(i == 2){											// 上移
		nx = bx - 1;									// 左移
		ny = by;
	}else if(i == 3){
		nx = bx;
		ny = by - 1;
	}
	if(nx < 0 || nx > n || ny < 0 || ny > n){			// 越界
		return false;
	}else{
		return true;	
	}

}

算法二:两次动态规划+贪心(假设第一次的动态规划解为整体最优解第一步最优解的基础上进行第二次动态规划),但是结果不完全对 。

#include<iostream>
#include<cstring>
#define MAX 15
using namespace std;

int main(){
	int n;
	int i, j, v;
	int dp[MAX][MAX];						// 动态规划二维数组
	int map[MAX][MAX];						// 记录地图
	int dir[MAX][MAX];						// 记录每一步走的方向,0为上,1为左
	int ans = 0;							// 最终结果
	memset(dp, 0, sizeof(dp));				// 矩阵初始化
	memset(map, 0, sizeof(map));
	cin >> n;
	cin >> i >> j >> v;
	while(i != 0 || j != 0 || v != 0){		// 读入数据
		map[i][j] = v;
		cin >> i >> j >> v;
	}
	for(i = 1; i <= n; i++){				// 第一次动态规划	
		for(j = 1; j <= n; j++){			// 状态转移方程
			dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + map[i][j];
			if(dp[i - 1][j] > dp[i][j - 1]){
				dir[i][j] = 0;
			}else{
				dir[i][j] = 1;
			}
		}
	}
	i = n, j = n;
	ans += dp[n][n];						// 第一次行走的最大值
	while(i !=0 && j != 0){					// 倒着寻找路径,并置零
		map[i][j] = 0;
		if(dir[i][j] == 0){
			i--;
		}else{
			j--;
		}
	}
	memset(dp, 0, sizeof(dp));				// 再次初始化
	for(i = 1; i <= n; i++){				// 第二次动态规划
		for(j = 1; j <= n; j++){
			dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + map[i][j];
		}
	}
	ans += dp[n][n];						// 加上第二次行走的最大值
	cout << ans << endl;
	return 0;
}

算法三:四维数组动态规划,两个人一起走。

#include<iostream>
#include<cstring>
#define MAX 15 
using namespace std;

int main(){
	int map[MAX][MAX];
	int dp[MAX][MAX][MAX][MAX];
	memset(map, 0, sizeof(map));
	memset(dp, 0, sizeof(dp));
	int n;
	int i, j, k, l, v;
	cin >> n;
	while(cin >> i >> j >> v){
		if(i == 0 && j ==0 && v == 0){
			break;
		}else{
			map[i][j] = v;
		}
	}
	for(i = 1; i <= n; i++){
		for(j = 1; j <= n; j++){
			for(k = 1; k <= n; k++){
				for(l = 1; l <= n; l++){
					// 状态转移方程
					int temp1 = max(dp[i - 1][j][k - 1][l], dp[i - 1][j][k][l - 1]);
					int temp2 = max(dp[i][j - 1][k - 1][l], dp[i][j - 1][k][l - 1]);
					dp[i][j][k][l] = max(temp1, temp2) + map[i][j];
					// 是否在同一点
					if(i != k){
						dp[i][j][k][l] += map[k][l];
					}
				}
			}
		}
	}
	cout << dp[n][n][n][n] << endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jsj小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值