20250901 - 搜索 总结

前言

今天罚时有亿点多!!!

搜索的概念

俗话说得好:不撞南墙不回头。

深度优先搜索 : Depth First Search 就是这个原理,不管怎样,直接往下搜,发现访问过了直接回溯。

广度优先搜索 : Breadth First Search ,把它比作水滴,一圈一圈往外扩散,所以他是一层一层往下搜的。

0-1bfs :0-1 Breadth First Search(瞎猜的) ,用双端队列,

bfs性质:

性质1:若队首为第i层拓展到的节点,则队列中最多只能存在第i层和第i+1层的节点,不可能出现3层节点。

性质2:队列中的元素会严格按照层数单调递增,而且会按照入队的先后来判别拓展的优先程度,即先入队的一定是更优先的,而越往后越次之。

如果图只有两个不同的边权,那么就可以一个边权放在队头,一个放在对尾,这是什么数据结构呢? vector deque

例题:

T1 全排列问题

全排列,用 next_permutation 深搜(我一开始也写的 next_permutation),记录 vis 数组,看有不有出现过,然后 dfs 记录就完了!

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 1e5 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n;
int a[MAXN];
void solve(){
	scanf("%d",&n);
	for(int i = 1;i <= n;i++)
		a[i] = i;
	do{
		for(int i = 1;i <= n;i++){
			printf("    %d",a[i]);
		}
		printf("\n");
	}while(next_permutation(a+1,a+n+1));
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

额,不是这个!!!

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 1e5 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t;
int n,c[10];
bool b[10];
void dfs(int i){
	if(i == n + 1){
		for(int j = 1;j <= n;j++){
			printf("    %d",c[j]);
		}
		printf("\n");
		return;
	}
	for(int j = 1;j <= n;j++){
		if(!b[j]){
			b[j] = true;
			c[i] = j;
			dfs(i+1);
			b[j] = false;
		} 
	}
}
void solve(){
	scanf("%d",&n);
	dfs(1);
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T2 迷宫

直接 dfs,记录答案即可!!!

坑点来喽:起点也要设为 1。(吃了 2 发罚时)

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 10 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n,m,ts;
int sx,sy,fx,fy;
int mp[MAXN][MAXN];
bool vis[MAXN][MAXN];
int ans = 0;
const int dx[] = {-1,0,0,1};
const int dy[] = {0,-1,1,0};
void dfs(int x,int y){
	if(x == fx && y == fy){
		ans++;
		return;
	}else{
		for(int i = 0;i < 4;i++){
			int xx = x + dx[i];
			int yy = y + dy[i];
			if(xx > n || xx < 1 || yy < 1 || yy > m)
				continue;
			if(mp[xx][yy] || vis[xx][yy]) continue;
			vis[xx][yy] = 1;
			dfs(xx,yy);
			vis[xx][yy] = 0;
		}
	}
}
void solve(){
	scanf("%d%d%d",&n,&m,&ts);
	scanf("%d%d%d%d",&sx,&sy,&fx,&fy);
	while(ts--){
		int x,y;
		scanf("%d%d",&x,&y);
		mp[x][y] = 1;
	}
	mp[sx][sy] = 1;
	dfs(sx,sy);
	printf("%d\n",ans);
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T3 Lake Counting S

没啥写的,就是一道连通块板子题(呃呃呃,不是用并查集)

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 100 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n,m;
char s[MAXN][MAXN];
int vis[MAXN][MAXN];
const int dx[] = {-1,-1,-1,0,0,1,1,1};
const int dy[] = {-1,0,1,-1,1,-1,0,1};
void dfs(int x,int y){
	vis[x][y] = 1;
	for(int i = 0;i < 8;i++){
		int xx = x + dx[i];
		int yy = y + dy[i];
		if(xx > n || xx < 1 || yy < 1 || yy > m)
			continue;
		if(!vis[xx][yy] && s[xx][yy] == 'W')
			dfs(xx,yy);
	}
	return;
}
void solve(){
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++){
		scanf("%s",s[i]+1);
	}
	int ans = 0;
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= m;j++){
			if(!vis[i][j] && s[i][j] == 'W'){
				ans++;
				dfs(i,j);
			}
		}
	}
	printf("%d\n",ans);
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T4 离开中山路

简单网格图bfs(说啥我之前写了个dijkstra)

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 1000 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n;
int sx,sy,fx,fy;
int dis[MAXN][MAXN];
const int dx[] = {-1,0,0,1};
const int dy[] = {0,-1,1,0};
char s[MAXN][MAXN];
void bfs(int sx,int sy){
	queue<PII>q;
	memset(dis,-1,sizeof(dis));
	q.push({sx,sy});
	dis[sx][sy] = 0;
	while(!q.empty()){
		int x = q.front().first;
		int y = q.front().second;
		q.pop();
		for(int i = 0;i < 4;i++){
			int xx = x + dx[i];
			int yy = y + dy[i];
			if(xx > n || xx < 1 || yy < 1 || yy > n)
				continue;
			if(dis[xx][yy] != -1 || s[xx][yy] == '1')
				continue;
			dis[xx][yy] = dis[x][y] + 1;
			q.push({xx,yy});
		}
	}
}
void solve(){
	scanf("%d",&n);
	for(int i = 1;i <= n;i++){
		scanf("%s",s[i]+1);
	}
	scanf("%d%d%d%d",&sx,&sy,&fx,&fy);
	bfs(sx,sy);
	printf("%d\n",dis[fx][fy]);
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T5 取数游戏

额,非常的暴力,就是暴力在统计答案就好了!(多则不清空,爆零两行泪)

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 1e5 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int dx[] = {-1,-1,-1,0,0,1,1,1};
const int dy[] = {-1,0,1,-1,1,-1,0,1};
int t,n,m;
int ans = 0,step = 0;
int a[100][100],vis[100][100];
void dfs(int x,int y){
	if(y == m + 1){
		dfs(x+1,1);	
		return;
	}
	if(x == n + 1){
		ans = max(ans,step);
		return;
	}
	dfs(x,y+1);
	if(!vis[x][y]){
		step += a[x][y];
		for(int i = 0;i < 8;i++){
			++vis[x+dx[i]][y+dy[i]];
		}
		dfs(x,y+1);
		for(int i = 0;i < 8;i++){
			--vis[x+dx[i]][y+dy[i]];
		}
		step -= a[x][y];
	}
	return;
}
void solve(){
	ans = 0;
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= m;j++){
			scanf("%d",&a[i][j]);
		}
	}
	dfs(1,1);
	printf("%d\n",ans);
  return;
}
signed main(){
  scanf("%d",&t);
  while(t--){
    solve();
  }
  return 0;
}

T6 八皇后 Checker Challenge

呃呃呃,八皇后板子题

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 103 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n;
int c[MAXN];
bool b[MAXN],b1[MAXN],b2[MAXN];
int cnt = 0;
void dfs(int i){
	if(i == n + 1){
		cnt++;
		if(cnt <= 3){
			for(int j = 1;j <= n;j++){
				printf("%d ",c[j]);
			}
			printf("\n");
		}
		return;
	}
	for(int j = 1;j <= n;j++){
		if(!b[j] && !b1[i+j] && !b2[i-j+n]){
			c[i] = j;
			b[j] = b1[i+j] = b2[i-j+n] = 1;
			dfs(i+1);
			b[j] = b1[i+j] = b2[i-j+n] = 0;
		}
	}
}
void solve(){
	scanf("%d",&n);
	dfs(1);
	printf("%d\n",cnt);
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T7 马的遍历

bfs好题,思路:bfs

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 400 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n,m,x,y;
const int dx[] = {1,2,2,1,-1,-2,-2,-1};
const int dy[] = {-2,-1,1,2,2,1,-1,-2};
int dis[MAXN][MAXN];
queue<PII>q;
void bfs(int sx,int sy){
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= m;j++)
			dis[i][j] = -1;
	dis[sx][sy] = 0;
	q.push({sx,sy});
	while(!q.empty()){
		int x = q.front().first;
		int y = q.front().second;
		q.pop();
		for(int i = 0;i < 8;i++){
			int xx = x + dx[i];
			int yy = y + dy[i];
			if(xx > n || xx < 1 || yy < 1 || yy > m)
				continue;
			if(dis[xx][yy] != -1)
				continue;
			dis[xx][yy] = dis[x][y] + 1;
			q.push({xx,yy});
		}
	}
}
void solve(){
	scanf("%d%d%d%d",&n,&m,&x,&y);
	bfs(x,y);
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= m;j++){
			printf("%d ",dis[i][j]);
		}
		printf("\n");
	}
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T8 血色先锋队

这不是曼哈顿距离吗?

坑点:千万别用 array 和 vector!!!!!!

第一发罚时

第二发罚时

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 1e5 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n,m,a,b;
PII vs[MAXN],vp[MAXN];
int ve[MAXN];
void solve(){
	scanf("%d%d%d%d",&n,&m,&a,&b);
	fill(ve+1,ve+b+1,INF);
	for(int i = 1;i <= a;i++){
		scanf("%d%d",&vs[i].first,&vs[i].second);
	}
	for(int i = 1;i <= b;i++){
		scanf("%d%d",&vp[i].first,&vp[i].second);
	}
	for(int i = 1;i <= a;i++){
		for(int j = 1;j <= b;j++){
			ve[j] = min(ve[j],abs(vs[i].first-vp[j].first)+abs(vs[i].second-vp[j].second));
		}
	}
	for(int i = 1;i <= b;i++){
		printf("%d\n",ve[i]);
	}
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T9 好奇怪的游戏

马加相的走法就好了

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 1000 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n;
int sx,sy,fx,fy;
int dis[MAXN][MAXN];
const int dx[] = {1,1,2,2,2,2,-1,-1,-2,-2,-2,-2};
const int dy[] = {-2,2,-2,-1,1,2,-2,2,-1,1,-2,2};
char s[MAXN][MAXN];
void bfs(int sx,int sy){
	queue<PII>q;
	memset(dis,-1,sizeof(dis));
	q.push({sx,sy});
	dis[sx][sy] = 0;
	while(!q.empty()){
		int x = q.front().first;
		int y = q.front().second;
		q.pop();
		for(int i = 0;i < 12;i++){
			int xx = x + dx[i];
			int yy = y + dy[i];
			if(xx > 50 || xx < 1 || yy < 1 || yy > 50)
				continue;
			if(dis[xx][yy] != -1)
				continue;
			dis[xx][yy] = dis[x][y] + 1;
			q.push({xx,yy});
		}
	}
}
void solve(){
	scanf("%d%d%d%d",&sx,&sy,&fx,&fy);
	bfs(sx,sy);
	printf("%d\n",dis[1][1]);
	bfs(fx,fy);
	printf("%d\n",dis[1][1]);
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T10 面试

全排列一下就好了

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 20 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n,k;
array<pair<int,int>,MAXN>a;
array<int,MAXN>b,c,vis; 
bool ok = 1;
void dfs(int i){
	if(i == k + 1){
		if(ok){
			for(int j = 1;j <= n;j++){
				printf("%d ",c[j]);
			}
		}
		ok = 0;
		return;
	}
	for(int j = 1;j <= n;j++){
		if(!vis[j] && a[j].first >= b[i]){
			vis[j] = true;
			c[i] = j;
			dfs(i+1);
			vis[j] = false;
		} 
	}
}
void solve(){
	scanf("%d%d",&n,&k);
	for(int i = 1;i <= n;i++){
		scanf("%d",&a[i].first);
		a[i].second = i;
	}
	for(int i = 1;i <= k;i++)
		scanf("%d",&b[i]);
	dfs(1);
	if(ok)
		puts("-1");
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T11 Labyrinth

思路:0-1bfs,把上下边权设为 0 ,左右设为 1。

有点麻烦,不如 dijkstra

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int ll
#define db double
//#define TS
typedef pair<int,int> PII;
const int MAXN = 4000 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t,n,m;
int sx,sy,fx,fy;
int dis[MAXN][MAXN];
const int dx[] = {-1,0,0,1};
const int dy[] = {0,-1,1,0};
char s[MAXN][MAXN];
int ans = 0;
void bfs(){
	deque<array<int,4>>q;
	memset(dis,-1,sizeof(dis));
	q.push_front({sx,sy,fx,fy});
	while(!q.empty()){
		array<int,4>tmp;
		tmp = q.front();
		int x = tmp[0],y = tmp[1];
		q.pop_front();
		if(tmp[2] < 0 || tmp[3] < 0)
			continue;
		if(dis[x][y] != -1) continue;
		dis[x][y] = 1;
		ans++;
		for(int i = 0;i < 4;i++){
			int xx = x + dx[i];
			int yy = y + dy[i];
			if(xx > n || xx < 1 || yy < 1 || yy > m)
				continue;
			if(dis[xx][yy] != -1 || s[xx][yy] == '*')
				continue;
			if(i == 0 || i == 3){
				q.push_front({xx,yy,tmp[2],tmp[3]});
			}else if(i == 1){
				q.push_back({xx,yy,tmp[2]-1,tmp[3]});
			}else{
				q.push_back({xx,yy,tmp[2],tmp[3]-1});
			}
		}
	}
}

void solve(){
	scanf("%lld%lld",&n,&m);
	scanf("%lld%lld",&sx,&sy);
	scanf("%lld%lld",&fx,&fy);
	for(int i = 1;i <= n;i++){
		scanf("%s",s[i]+1);
	}
	bfs();
	printf("%lld\n",ans);
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

T12 Telephone Lines S

嗨嗨嗨,这道题我写过(额,有点复杂)

二分价格,跑 dijkstra 0-1bfs 看是否能到达(不如跑 dijkstra)

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
typedef pair<int,int> PII;
const int MAXN = 1e3 + 7;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int t;
int n,m,k;
vector<PII>edges[MAXN],ve[MAXN];
int l,r;
array<int,MAXN>dis,vis;
int bfs(int s) {
  fill(dis.begin(), dis.end(), -1);
  fill(vis.begin(), vis.end(), 0);
  deque<int> q;
  q.push_front(s);
  dis[s] = 0;
  while (!q.empty()) {
    int u = q.front();
    q.pop_front();
    if (vis[u]) continue;
    vis[u] = 1;
    for (auto v : edges[u]) {
      int to = v.first, val = v.second;
      if (dis[to] == -1 || dis[to] > dis[u] + val) {
        dis[to] = dis[u] + val;
        if (val == 0) {
          q.push_front(to);
        } else {
          q.push_back(to);
        }
      }
    }
  }
  return dis[n];
}
bool check(int x){
	for(int i = 1;i <= n;i++){
		edges[i].clear();
	}
	for(int i = 1;i <= n;i++){
		for(auto v : ve[i]){
			if(v.second < x){
				edges[i].push_back({v.first,0});
			}else{
				edges[i].push_back({v.first,1});
			}
		} 
	}
	int val = bfs(1);
	return val <= k;
}
void solve(){
	scanf("%d%d%d",&n,&m,&k);
	while(m--){
		int x,y,w;
		scanf("%d%d%d",&x,&y,&w);
		ve[x].push_back({y,w});
		ve[y].push_back({x,w});
		r = max(r,w);
	}
	l = 0;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(check(mid))
			r = mid - 1;
		else
			l = mid + 1;
	}
	printf("%d\n",r);
  return;
}
signed main(){
  t = 1;
  while(t--){
    solve();
  }
  return 0;
}

posted @ 2025-09-01 20:32  Ruochen_xia  阅读(17)  评论(0)    收藏  举报