挖地雷
挖地雷
https://www.luogu.com.cn/problem/P2196
前言:
emmm...最开始接触这道题,是在学深搜的时候(具体哪本书忘了)那时候还做不来,就听老师讲了之后直接交的代码,并没有多大的感悟。
为了CSP,又开始复习(重学)万能的深搜;再加上想练习一下 vector ,于是重新编了一遍。交了三遍AC了。
思路:
1、题目中:“某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。”
很明显就是 DFS嘛!尝试所有N个洞作为起始点,不断探索与之相连的点(洞),把每一种方案的结果记录下来再比较最大,完事!
2、不过,这道题还要求输出最大值的路径。我认为这才是这道题的难点(最大值直接套深搜板子就好)。那就用一个数组 nxt记录路径。每当更新最多地雷数的时候,顺便也将路径更新。当然,要用另外一个数组sum保存。
具体的见代码注释吧
#include <bits/stdc++.h>
using namespace std;
int n,x,k,ans,tot,nxt[10010],a[10010],sum[10010],p[10010];
vector<int> ssty[10010];
inline void dfs(int x,int y,int tot) { //x记录位置,走了y个点,tot是当前的地雷数
bool pd=false; //判断当前方案是否走到极点
for(register int i=0; i<ssty[x].size(); i++) { //与x点相连的点
if(p[ssty[x][i]]==0) { //没有走过
pd=true; //方案没有结束
p[ssty[x][i]]=1; //标记为走过
nxt[y+1]=ssty[x][i]; //记录路径
dfs(ssty[x][i],y+1,tot+a[ssty[x][i]]); //从这个点继续向下挖
p[ssty[x][i]]=0; //回溯必备
}
}
if(pd==false) {
if(ans<tot) { //如果最大值更改,说明路径也要改变
ans=tot;
k=y;
for(register int i=1; i<=y; i++) sum[i]=nxt[i]; //将最大值路径复制在sum数组中
}
return;
}
}
int main() {
scanf("%d",&n);
for(register int i=1; i<=n; i++) scanf("%d",&a[i]);
for(register int i=1; i<n; i++) { //题目要求的输入
for(register int j=i+1; j<=n; j++) {
scanf("%d",&x);
if(x==1) ssty[i].push_back(j); //将与 i 洞相连的点加入“队列”
}
}
for(register int i=1; i<=n; i++) { //尝试每一个点
p[i]=1; //标记为已走过
nxt[1]=i; //将第一个洞设为自己
dfs(i,1,a[i]);
p[i]=0;
}
for(register int i=1; i<=k; i++) printf("%d ",sum[i]); //最终的最大值路径
printf("\n%d",ans); //最多能挖到的地雷数
return 0;
}
深搜,一种把板子套上去就差不多成功一半的神奇算法QVQ
如果这篇题解有任何问题,欢迎指正,谢谢!
From:Eleven谦