挖雷问题

题目描述:

在一个地图上有N个地窖(N<=200),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径,并规定路径都是单向的。某人可以从任一处开始挖地雷,然后沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使他能挖到最多的地雷。

Input

N {地窖的个数} 
W1,W2,……WN {每个地窖中的地雷数} 
X1,Y1 {表示从X1可到Y1} 
X2,Y2 
…… 
0,0 {表示输入结束} 

Output

K1——K2——……——Kv {挖地雷的顺序} 
MAX {最多挖出的地雷数} 


这一题的动态规划是从后往前计算,也就是从拓扑排序的最后一个开始不断的往前计算

本题是一个经典的动态规划问题。很明显,题目规定所有路径都是单向的,所以满足无后效性原则最优化原理

1、用动态规划求解:  

(1)由后往前查找: 若从第n个地雷坑开始挖,此时可能得到a(n)枚地雷。 若从第n-1个地雷坑开始挖,此时有2种可能:   ①第n-1个到第n个地雷坑无法走通(可由r(n-1,n)判断),此时可挖a(n-1)枚。  ②第n-1个到第n个地雷坑可以走通,则可挖a(n-1)+a(n)枚。   一般情况,若从第i个地雷坑开始挖,根据关系r,找出i后面的所有可以走通的地雷坑,从中找出一条可挖最多地雷的路线,这样可得到最多的挖地雷数。   

(2)上面计算出从每个地雷坑开始能挖到最多的地雷数,此时找出一个最大值即可。

这也是一个显然的线性动态规划的问题。

代码如下:

#include<iostream.h>
#define max 100//定义最大地雷坑数
int main()
{
//初始化
	int a[max]={0};//记录地雷坑地雷个数
	int r[max][max]={0};//r[i][j]记录从i到j地雷坑是否走的通
	int b[max][3]={0};//b[][1]记录挖出雷德总数,b[][2]记录挖出雷位置
	int i,j,h,cmax;
	int n;
//数据输入
	cout<<"请输入地雷坑的个数:";
	cin>>n;
	cout<<"请输入地雷坑里雷的个数:";
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(i=1;i<=n;i++)
	{
		for(j=i;j<=n;j++)
		{
			if (j==i)cout<<"请输入第"<<i<<"行,从"<<j<<"开始是否走的通:";
			
			cin>>r[i][j];
		}
	}
//动态规划算法开始
	for(i=n;i>0;i--)//从最后一个地雷坑开始
	{
		cmax=0;h=0;
		for(j=i;j<=n;j++)
		{
			if(r[i][j]==1 && b[j][1]>cmax)//找到第i到第j的坑是否走的通,并找出最大值
			{
				h=j;
				cmax=b[j][1];
			}
			b[i][1]=a[i]+cmax;//记录当前获得地雷的总数
			b[i][2]=h;//记录地雷坑的位置
		}
		
	}
	cmax=0;
	h=0;
	for(i=1;i<=n;i++)//找出记录中最大地雷总数
	{
		if(b[i][1]>cmax)
		{
			h=i;
			cmax=b[i][1];
		}
	}
	cout<<"挖出最多雷数为:"<<cmax<<endl;
	if(h!=0)cout<<"挖地雷的路径为:"<<h;//输出查出最大地雷的路径
	while(b[h][2]!=0)
	{
		h=b[h][2];
		cout<<"--->"<<h;
	}
	cout<<endl;
	
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自动挖雷程序需要实现以下几个步骤: 1. 使用图像识别技术识别出雷区的布局; 2. 根据雷区的布局,计算出每个格子周围的雷数; 3. 根据计算出的雷数,推断出每个格子的状态(是否是雷、是否已经被翻开、是否可以被翻开等); 4. 根据推断出的格子状态,进行自动翻开操作,直到所有非雷格子都被翻开。 下面是一个简单的 C++ 实现: ```cpp #include <iostream> #include <cstring> using namespace std; const int MAXN = 105; char mine[MAXN][MAXN]; bool visited[MAXN][MAXN]; int n, m; void dfs(int x, int y) { visited[x][y] = true; if (mine[x][y] != '0') return; for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { int nx = x + dx, ny = y + dy; if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny]) { dfs(nx, ny); } } } } int main() { cin >> n >> m; memset(mine, '.', sizeof(mine)); memset(visited, false, sizeof(visited)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> mine[i][j]; } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (mine[i][j] == '0' && !visited[i][j]) { dfs(i, j); } } } int cnt = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (mine[i][j] != '*' && visited[i][j]) { cnt++; } } } cout << cnt << endl; return 0; } ``` 这个程序使用深度优先搜索来实现自动翻开操作,其中 `mine` 数组用来存储雷区的布局,`visited` 数组用来记录哪些格子已经被翻开。程序首先读入雷区的布局,然后对于每个未翻开的格子,使用深度优先搜索来翻开它周围的格子,直到无法再翻开为止。最后统计一下被翻开的格子数量即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值