P2196 [NOIP1996 提高组] 挖地雷

[NOIP1996 提高组] 挖地雷

题目描述

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

输入格式

有若干行。

有若干行。

第1行只有一个数字,表示地窖的个数N。

第2行有N个数,分别表示每个地窖中的地雷个数。

第3行至第N+1行表示地窖之间的连接情况:

第3行有n−1个数(0或1),表示第一个地窖至第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表示有路径)。

输出格式

有两行

第一行表示挖得最多地雷时的挖地雷的顺序,各地窖序号间以一个空格分隔,不得有多余的空格。

第二行只有一个数,表示能挖到的最多地雷数。

样例 #1

样例输入 #1

5
10 8 4 7 6
1 1 1 0
0 0 0
1 1
1

样例输出 #1

1 3 4 5
27

提示

【题目来源】

NOIP 1996 提高组第三题

讲解

这道题在洛谷里的标签:动态规划,dp
搜索
深度优先搜索,DFS
这里我选的方法为dfs
由题意可得这是一个有向图,所以输入

for(int i=1;i<n;i++){//f数组是地窖的连接情况
	for(int j=i+1;j<=n;j++){
		cin>>f[i][j];
	}
}

然后我用数组b(一维)来标记有没有走过(一个标记数组)
数组step来记录路径(一维)
数组ans来记录最终的路径
其他的变量在代码中会有
本题的核心就是dfs怎样调用
先看dfs代码

void dfs(int x,int set,int sum){//x是指当前位置,set是指路径总长度,sum是指挖的地雷总数
	if(fun(x)){//这里的fun函数是判断是否还能往下去挖地雷,也就是还有没有路径
		if(maxx<sum){//取最大值
			maxx=sum;//挖的总地雷数
			cnt=set;//路径长度
			for(int i=1;i<=set;i++){
				ans[i]=step[i];//把路径赋给ans
			}
		}
		return ;
	}
	for(int i=1;i<=n;i++){
		if(f[x][i]&&!b[i]){//如果有路径并且没有走过
			b[i]=1;//把当前的位置标记一下
			step[set+1]=i;//记录当前位置
			dfs(i,set+1,sum+a[i]);//调用dfs函数(递归)
			b[i]=0;//回溯
		}
	}
}
bool fun(int x){//x是指当前的位置,这就是判断还能不能往下走的函数
	for(int i=1;i<=n;i++){
		if(f[x][i]&&!b[i])return false;//如果还有路径并且还没有走过,就返回家
	}
	return true;//如果在循环过程都没有返回假,那么就说明这个位置没法往下走了
}

以上就是本题的核心部分,来看一下

AC代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005];
int f[1005][1005];
int step[1005];
int b[10005];
int sum,cnt;
int maxx;
int ans[10005];
bool fun(int x){
	for(int i=1;i<=n;i++){
		if(f[x][i]&&!b[i])return false;
	}
	return true;
}
void dfs(int x,int set,int sum){
	if(fun(x)){
		if(maxx<sum){
			maxx=sum;
			cnt=set;
			for(int i=1;i<=set;i++){
				ans[i]=step[i];
			}
		}
		return ;
	}
	for(int i=1;i<=n;i++){
		if(f[x][i]&&!b[i]){
			b[i]=1;
			step[set+1]=i;
			dfs(i,set+1,sum+a[i]);
			b[i]=0;
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<n;i++){
		for(int j=i+1;j<=n;j++){
			cin>>f[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		b[i]=1;//标记当前位置,避免到函数里运算错误
		step[1]=i;//记录当前位置,当做起始位置
		dfs(i,1,a[i]);//进入函数
		b[i]=0;//回溯
	}
	for(int i=1;i<=cnt;i++){
		cout<<ans[i]<<" ";
	}
	cout<<endl<<maxx;
	return 0;
}

如果各位觉得本题有讲解不得当的地方,请在评论区留言,灰常感谢!!!

posted @   I-am-coding!  阅读(70)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示