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;
}
如果各位觉得本题有讲解不得当的地方,请在评论区留言,灰常感谢!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)