「Day 3—深度优先搜索 & 广度优先搜索」
深度优先搜索
定义
简单来说就是,一条路走到死,不行的话就回溯,继续一条路走到死,直到抵达目标点。
习题
P2052 [NOI2011] 道路修建
思路
首先,看题目对于花费的定义,道路的长度*道路两端国家数的差值的绝对值,观察一下这个应该怎么计算,我们很明显能想到树子树大小,于是我们只要知道其中一个的子树大小 \(size\),那么另一个便是 \(n-size\),于是乎,花费\(=d\times |size-(n-size)| = dx|2\times size-n|\),那么用链式前向星存一下各个国家的关系,再 \(dfs\) 去统计花费。
代码
#include<iostream>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
#define int long long
struct node{
int to,next,len;
}e[2 * 1000005];
int h[1000005];
int tot = 0;
inline void adge(int x,int y,int len){
e[++ tot] = (node){y,h[x],len};
h[x] = tot;
return;
}
int n,m,ans=0,maxx=-1;
int size[1000005];
void dfs(int x,int f){
size[x] = 1;
for(int i = h[x];i != -1;i = e[i].next){
int v = e[i].to;
if(v != f){
dfs(v,x);
size[x] += size[v];
ans += e[i].len * abs(n - 2 * size[v]);
}
}
}
signed main(){
memset(h,-1,sizeof(h));
cin >> n;
for(int i = 1;i < n;i ++){
int u,v,w;
cin >> u >> v >> w;
adge(u,v,w);
adge(v,u,w);
}
dfs(1,0);
cout << ans << "\n";
return 0;
}
P1434 [SHOI2002] 滑雪
思路
这个题说实话挺水的,就正常 \(dfs\),加上一个条件,即当前必须大于下一个,然后用数组记录最大的。但是但是但是,这样会超时 \(4\) 个点,为什么呢,原因是我们做了 \(n * n\) 次 \(dfs\),而有些点搜了不止一次,于是我们就想到了记忆化。
代码
#include<iostream>
using namespace std;
int n,m;
int mp[105][105];
int vis[105][105];
int dxy[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
int dfs(int x,int y){
if(vis[x][y]) return vis[x][y];
vis[x][y] = 1;
for(int i = 0;i < 4;i ++){
int dx = x + dxy[i][0];
int dy = y + dxy[i][1];
if(dx > 0 && dy > 0 && dx <= n && dy <= m && mp[x][y] > mp[dx][dy]){
dfs(dx,dy);
vis[x][y] = max(vis[x][y],vis[dx][dy] + 1);
}
}
return vis[x][y];
}
int ans = 0;
int main(){
cin >> n >> m;
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= m;j ++){
cin >> mp[i][j];
}
}
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= n;j ++){
ans = max(ans,dfs(i,j));
}
}
cout << ans << "\n";
return 0;
}
P2853 [USACO06DEC] Cow Picnic S
思路
首先,这个题看起来很简单,就把所有牧场全 \(dfs\) 一次,如果这个点能到含有奶牛的牧场==k时,这个点就没什么问题,\(ans++\) 即可,但是但是但是牧场有\(<=1e4\)个,边有\(<=1e5\) 条,所以这样跑肯定有问题,于是我们想到反过来,既然不从点去找牛,就让牛去找牧场,以每个牛所在的位置开始 \(dfs\),如果一个点被经过了 \(k\) 次,那么这个点一定就是所以奶牛可到达的地方。理论成立,代码如下:
代码
#include<iostream>
#include<cstring>
using namespace std;
int k,n,m;
int x[100005];
struct node{
int to,next;
}e[2 * 100005];
int h[100005];
bool vis[100005];
int cnt[100005];
int tot = 0;
inline void adge(int x,int y){
e[++ tot] = (node){y,h[x]};
h[x] = tot;
return;
}
void dfs(int x){
cnt[x] ++;
for(int i = h[x];i != -1;i = e[i].next){
int v = e[i].to;
if(!vis[v]){
vis[v] = 1;
dfs(v);
}
}
return;
}
int main(){
memset(h,-1,sizeof(h));
cin >> k >> n >> m;
for(int i = 1;i <= k;i ++){
cin >> x[i];
}
for(int i = 1;i <= m;i ++){
int u,v;
cin >> u >> v;
adge(u,v);
}
for(int i = 1;i <= k;i ++){
vis[x[i]] = 1;
dfs(x[i]);
memset(vis,0,sizeof(vis));
}
int ans = 0;
for(int i = 1;i <= n;i ++){
if(cnt[i] == k){
ans ++;
}
}
cout << ans << "\n";
return 0;
}
P8604 [蓝桥杯 2013 国 C] 危险系数
思路
因为我们要求其关键点个数,所以呢我们可以“人性”一点,每次封锁一个点,跑一遍 \(dfs\),如果不能到终点,那么这个点就是关键点。
代码
#include<vector>
#include<iostream>
#include<cstring>
using namespace std;
vector<int> G[1005];
int n,m,ans = 0;
int fx,fy;
bool v1[1005]={0,0};
bool r[1005]={0,0};
void dfs(int x){
if(v1[x]) return;
if(r[x]) return;
v1[x] = 1;
for(auto v:G[x]){
dfs(v);
}
return;
}
int main(){
cin >> n >> m;
for(int i = 1;i <= m;i ++){
int u,v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
cin >> fx >> fy;
dfs(fx);
if(v1[fy] == 0){
cout << "-1\n";
return 0;
}
for(int i = 1;i <= n;i ++){
if(i == fx || i == fy){
continue;
}
memset(v1,0,sizeof(v1));
r[i] = 1;
dfs(fx);
r[i] = 0;
if(v1[fy] == 0){
ans ++;
}
}
cout << ans <<"\n";
return 0;
}
P1294 高手去散步
思路
首先,用链式前向星存一下信息,为了使他们达到最长的相伴距离,那么就是找一条路,使其边权和最大,如何操作呢,我们可以从 \(n\) 个点各跑一遍 \(dfs\),在跑的过程中记录最大的,然后输出即可。
代码
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
struct node{
int to,next,len;
}e[10005];
int h[10005];
int vis[10005];
int tot = 0;
inline void adge(int x,int y,int len){
e[++ tot] = (node){y,h[x],len};
h[x] = tot;
return;
}
int n,m,ans=0,maxx=-1;
void dfs(int x){
for(int i = h[x];i != -1;i = e[i].next){
int v = e[i].to;
int w = e[i].len;
if(vis[v] == 0){
vis[v] = 1;
ans += w;
maxx = max(maxx,ans);
dfs(v);
ans -= w;
vis[v] = 0;
}
}
}
int main(){
memset(h,-1,sizeof(h));
cin >> n >> m;
for(int i = 1;i <= m;i ++){
int u,v,w;
cin >> u >> v >> w;
adge(u,v,w);
adge(v,u,w);
}
for(int i = 1;i <= n;i ++){
vis[i] = 1;
dfs(i);
vis[i] = 0;
}
cout << maxx << "\n";
return 0;
}
P6207 [USACO06OCT] Cows on Skates G
思路
这个题吧,求 \((1,1)\) 到 \((r,c)\)的一条任意路径,我们选择 \(dfs\),顺便记录路径。
代码
#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
char mp[150][150];
int pathx[100005];
bool vis[150][150];
int pathy[100005];
int dxy[4][2] = {{1,0},{0,-1},{-1,0},{0,1}};
void dfs(int x,int y,int id){
pathx[id] = x;
pathy[id] = y;
if(x == n && y == m){
for(int i = 1;i <= id;i ++){
cout << pathx[i] << " " << pathy[i] << "\n";
}
}
for(int i = 0;i < 4;i ++){
int dx = x + dxy[i][0];
int dy = y + dxy[i][1];
if(dx < 1 || dx > n || dy < 1 || dy > m || mp[dx][dy] == '*' || vis[dx][dy]){
continue;
}
vis[dx][dy] = 1;
dfs(dx,dy,id+1);
}
}
int main(){
cin >> n >> m;
for(int i = 1;i <= n;i ++){
scanf("%s",mp[i] + 1);
}
vis[1][1] = 1;
dfs(1,1,1);
return 0;
}
广度优先搜索
定义
别名“宽度优先搜索”,每次向下搜,一层一层搜。
习题
P1330 封锁阳光大学
思路
简单看下,发现无从下手,手动推一下,发现这是个染色问题,于是就 \(bfs\) +染色,每次选最小的。
代码
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
struct node{
int to,next;
}e[500005];
int h[500005],color[500005],cnt[5];
int vis[500005];
int tot = 0;
inline void adge(int x,int y){
e[++ tot] = (node){y,h[x]};
h[x] = tot;
return;
}
int n,m,maxx=-0;
bool bfs(int x){
queue<int> q;
q.push(x);
color[x] = 1;
cnt[1] = 1,cnt[2] = 0;
while(!q.empty()){
int v = q.front();
q.pop();
for(int i = h[v];i != -1;i = e[i].next){
int t = e[i].to;
if(color[t] == color[v]){
return 1;
}
if(color[t] == 0){
color[t] = color[v] % 2 + 1;
cnt[color[t]] ++;
q.push(t);
}
}
}
return 0;
}
int main(){
memset(h,-1,sizeof(h));
cin >> n >> m;
for(int i = 1;i <= m;i ++){
int u,v;
cin >> u >> v;
adge(u,v);
adge(v,u);
}
for(int i = 1;i <= n;i ++){
if(color[i]) continue;
if(bfs(i)){
cout << "Impossible" << "\n";
return 0;
}
maxx += min(cnt[1],cnt[2]);
}
cout << maxx << "\n";
return 0;
}
本文来自一名初中牲,作者:To_Carpe_Diem