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;
}