动态规划的引入2

动态规划的引入-挖地雷

继续昨天的练习,今天又做了题单里的一些题,选了一道比较有意思的题作为本文内容。
题目: 挖地雷
题目内容:
在一个地图上有NN个地窖(N \le 20)(N≤20),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径。当地窖及其连接的数据给出之后,某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使某人能挖到最多的地雷。
输入格式:
有若干行。
第1行只有一个数字,表示地窖的个数N。
第2行有N个数,分别表示每个地窖中的地雷个数。
第3行至第N+1行表示地窖之间的连接情况:
第3行有n-1个数(00或11),表示第一个地窖至第2个、第3个、…、第n个地窖有否路径连接。如第3行为11000…0,则表示第1个地窖至第2个地窖有路径,至第3个地窖有路径,至第4个地窖、第5个、…、第n个地窖没有路径。
第4行有n-2个数,表示第二个地窖至第3个、第4个、…、第n个地窖有否路径连接。
… …
第n+1行有1个数,表示第n-1个地窖至第n个地窖有否路径连接。(为0表示没有路径,为1表示有路径)。
输出格式:
有两行,第一行表示挖得最多地雷时的挖地雷的顺序,各地窖序号间以一个空格分隔,不得有多余的空格。第二行只有一个数,表示能挖到的最多地雷数。
输入输出样例:
输入
5
10 8 4 7 6
1 1 1 0
0 0 0
1 1
1

输出
1 3 4 5
27
解题过程:
每个地窖的属性比较多,所以用了一个结构体来存储,mineNum表示该地窖藏得地雷数目,mineMax表示通往当前地窖的地雷数和最大的那条路的地雷数(算上本身),pre是在地雷数最多的那条路该结点的前驱结点,link存储通往该地窖的所有前驱结点。

struct{
	int mineNum;
	int mineDp;
	int mineMax;
	int pre;
	vector<int> link;
}cellar[100]; 

在通往当前地窖的地雷数和最大的那条路的地雷数 与 前一个地窖的dp值 做选择,这里顺便还存储了前驱结点,方便之后输出路径,代码如下:

void dp(){
	for(int i=2;i <= cellarNum;i++){
		cellar[i].mineMax = 0;
		for(int j=0;j<cellar[i].link.size();j++){
			//比较出哪条通往该地窖的路的地雷最多 
			if(cellar[i].mineMax < cellar[cellar[i].link[j]].mineMax){
				cellar[i].mineMax = cellar[cellar[i].link[j]].mineMax;  
				cellar[i].pre = cellar[i].link[j]; //存储前驱结点 
			}
		}
		cellar[i].mineMax += cellar[i].mineNum;
		cellar[i].mineDp = max(cellar[i].mineMax,cellar[i-1].mineDp);
	}  
}

代码写完了第一次交没过,仔细看了下题才发现还要输出路径,想了很久没想出来怎么在现基础上输出(不想重写代码),后来借鉴了一个题解,存储前驱结点,最后用递归的方式输出路径:

void showWay(int x){
	if(cellar[x].pre == 0) {
		cout << x << " " ;
		return;
	}
	else showWay(cellar[x].pre);
	cout << x << " ";
}

全部代码:

#include<bits/stdc++.h>
using namespace std;
//通往当前地窖的地雷数和最大的那条路的地雷数 与 前一个地窖的dp值 做选择
struct{
	int mineNum;
	int mineDp;
	int mineMax;
	int pre;
	vector<int> link;
}cellar[100]; 
int cellarNum;
void init(){
	cin >> cellarNum;
	for(int i=1;i <= cellarNum;i++){
		cin >> cellar[i].mineNum;
	}	
	for(int i=1;i < cellarNum;i++){
		for(int j=i+1;j <= cellarNum;j++){
			int x;
			cin >> x;
			if(x==1) cellar[j].link.push_back(i);
		}
	}
	cellar[1].mineDp = cellar[1].mineNum;
	cellar[1].mineMax = cellar[1].mineNum;
	cellar[1].pre = 0;
}
void showWay(int x){
	if(cellar[x].pre == 0) {
		cout << x << " " ;
		return;
	}
	else showWay(cellar[x].pre);
	cout << x << " ";
}
void dp(){
	for(int i=2;i <= cellarNum;i++){
		cellar[i].mineMax = 0;
		for(int j=0;j<cellar[i].link.size();j++){
			//比较出哪条通往该地窖的路的地雷最多 
			if(cellar[i].mineMax < cellar[cellar[i].link[j]].mineMax){
				cellar[i].mineMax = cellar[cellar[i].link[j]].mineMax;  
				cellar[i].pre = cellar[i].link[j]; //存储前驱结点 
			}
		}
		cellar[i].mineMax += cellar[i].mineNum;
		cellar[i].mineDp = max(cellar[i].mineMax,cellar[i-1].mineDp);
	}  
}
int main(){
	init();
	dp();
	for(int i=1;i<=cellarNum;i++){
		if(cellar[i].mineMax == cellar[cellarNum].mineDp){
			showWay(i);
			cout << endl;
			break;
		}
	}
	cout << cellar[cellarNum].mineDp;
} 

心得:
在题解里发现的用递归来输出路径的方法很有意思,很多题目应该都可以用到。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

asdfghtyjukilo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值