搜索模板题
广搜
洛谷–P1443 马的遍历(广搜)
#include<bits/stdc++.h>
using namespace std;
const int N=401;
int a[N][N];
int n,m,x,y;
int vis[N][N];
int dt[8][2]={
{
-1,2},{
-2,1},{
-2,-1},{
-1,-2},{
1,2},{
1,-2},{
2,1},{
2,-1}};
struct node
{
int x,y,step;
};
queue<node>q;
void bfs()
{
while(!q.empty())
{
node t=q.front();
for(int i=0;i<8;i++)
{
int xx=t.x+dt[i][0];
int yy=t.y+dt[i][1];
if(xx>=1 && xx<=n && yy>=1 && yy<=m && !vis[xx][yy])
{
node emp;
emp.x=xx;
emp.y=yy;
emp.step=t.step+1;
q.push(emp);
vis[xx][yy]=1;
}
}
a[t.x][t.y]=t.step;
q.pop();
}
}
int main()
{
cin>>n>>m>>x>>y;
node t;
t.x=x,t.y=y,t.step=0;
vis[x][y]=1;
q.push(t);
bfs();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==x && j==y) cout<<0<<' ';
else if(!a[i][j]) cout<<-1<<' ';
else cout<<a[i][j]<<' ';
}
cout<<endl;
}
return 0;
}
洛谷–P1332 血色先锋队
多目标广搜题目,按照常规思路解题即可
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n,m,a,b;
bool vis[N][N];
int sx[100005][3]; //用来记录终点坐标
int mp[N][N]; //用来记录到达终点的步数
int dr[4][2]={
{
0,-1},{
0,1},{
1,0},{
-1,0}};
struct node //将点入队要用到结构体。
{
int x,y,steps;
};
queue <node> q;
void bfs()
{
while(!q.empty())
{
node t1=q.front();
for(int i=0;i<4;i++)
{
int xx=t1.x+dr[i][0];
int yy=t1.y+dr[i][1];
if(xx>=1 && xx<=n && yy>=1 && yy<=m && !vis[xx][yy])
{
vis[xx][yy]=1;
node t2;
t2.x=xx, t2.y=yy;
t2.steps = t1.steps+1;
q.push(t2);
}
}
mp[t1.x][t1.y] = t1.steps;
q.pop();
}
}
int main()
{
cin>>n>>m>>a>>b;
for(int i=1,x1,y1;i<=a;i++)
{
cin>>x1>>y1;
node nn;
nn.x=x1, nn.y=y1, nn.steps=0;
q.push(nn);
vis[x1][y1]=true; //初始化bool数组别忘了
}
for(int i=1;i<=b;i++)
{
cin>>sx[i][1]>>sx[i][2];
}
bfs();
for(int i=1;i<=b;i++)
{
cout<<mp[sx[i][1]][sx[i][2]]<<endl;
}
return 0;
}
图中找联通分量个数(广搜)
根据输入的图的邻接矩阵A,判断此图的连通分量的个数。请使用邻接矩阵的存储结构创建图的存储,并采用BFS优先遍历算法实现,否则不得分。
【输入形式】
第一行为图的结点个数n,之后的n行为邻接矩阵的内容,每行n个数表示。其中Ai=1表示两个结点邻接,而Ai=0表示两个结点无邻接关系。
【输出形式】
输出此图连通分量的个数。
【样例输入】
5
0 1 1 0 0
1 0 1 0 0
1 1 0 0 0
0 0 0 0 1
0 0 0 1 0
【样例输出】
2
#include<bits/stdc++.h>
using namespace std;
int n,a[101][101],b[101],ans;
//广度优先搜索
void bfs(int a[101][101],int x)
{
queue<int> q;
q.push(x); b[x]=1;
while(!q.empty())
{
for(int i=1;i<=n;i++)
if(a[x][i])
{
q.push(i);
a[i][x]=0;//防止循环搜索遍历
b[i]=1;
}
q.pop();
x=q.front();
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++)
{
if(!b[i])
{
bfs(a,i);
ans++;
}
}
cout<<ans<<endl;
return 0;
}
深搜
犯罪团伙
【题目描述】
此题必须采用邻接表的存储结构,建立图的存储,然后采用DFS遍历实现求解。否则不给分。
警察抓到了 n 个罪犯,警察根据经验知道他们属于不同的犯罪团伙,却不能判断有多少个团伙,但通过警察的审讯,知道其中的一些罪犯之间相互认识,已知同一犯罪团伙的成员之间直接或间接认识。有可能一个犯罪团伙只有一个人。请你根据已知罪犯之间的关系,确定犯罪团伙的数量。已知罪犯的编号从 1 至 n。
【输入】
第一行:n(<=1000,罪犯数量),第二行:m(<5000,关系数量)以下若干行:每行两个数:I 和 j,中间一个空格隔开,表示罪犯 i 和罪犯 j 相互认识。
【输出】
一个整数,犯罪团伙的数量。
【样例输入】
11
8
1 2
4 3
5 4
1 3
5 6
7 10
5 10
8 9
【输出】
3
#include<iostream>
#include<cstdio>
#include<cstring>
#include<time.h>
#include<algorithm>
#include<queue>
using namespace std;
bool a[502][502],p[502];
int b=1,t,n,f,ans,m;
void dfs(int x){
//删除点的函数
for(int i=1;i<=n;i++){
if(a[x][i]){
//如果x与i联通
a[x][i]=a[i][x]=0;//在邻接表中删掉两个点的联通
p[x]=p[i]=1;//记录已被记录的点
dfs(i);//继续搜索,传过去一个与x有关的节点,然后再次进入深搜函数,保证任何与i有关的节点都被删除
}
}
}
int main()
{
//fre();//文件的输入输出
cin>>n>>m;
for(int i=1;i<=m;i++){
//建立邻接表
int x,y;//临时变量
cin>>x>>y;//读入
a[x][y]=a[y][x]=1;//标记以建立邻接表
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]){
p[i]=p[j]=1;//记录点已被使用过
dfs(i);//搜索以删点,在这里注意传过去的是i而不是j,因为在上面的深搜函数中,要保证所有与i有关的节点都删除
ans++;//答案+1
}
for(int i=1;i<=n;i++)
if(!p[i])//不与任何点连通的点
ans++;//答案+1
cout<<ans;
}
洛谷-- P1162 填涂颜色
#include<bits/stdc++.h>
using namespace std;
int a[35][35],n;
void dfs(int x,int y)
{
if(x<0||x>n+1||y<0||y>n+1||a[x][y])
return;
a[x][y]=666;
dfs(x,y+1);
dfs(x,y-1);
dfs(x-1,y);
dfs(x+1,y);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
dfs(0,0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(a[i][j]==666) cout<<0<<' ';
else if(a[i][j]==1) cout<<1<<' ';
else cout<<2<<' ';
cout<<endl;
}
return 0;
}
洛谷–P2404 自然数的拆分问题
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int n,a[N]={
1};
void print(int k)
{
for(int i=1;i<k;i++)
cout<<a[i]<<' ';
cout<<endl;
}
void dfs(int x,int k)
{
if(x==0)
{
print(k);
return;
}
for(int i=a[k-1];i<=x;i++)
{
if(x-i>=0)
{
a[k]=i;
dfs(x-i,k+1);
}
}
}
int main()
{
cin>>n;
dfs(n,1);
return 0;
}
洛谷–P1219 [USACO1.5]八皇后(经典)
#include<bits/stdc++.h>
using namespace std;
int n;
int a[101],b[101],c[101],d[101];
int total;
void dfs(int x)
{
//处理边界问题
if(x>n)
{
total++;
//打印一组结果;
if(total<=3)
{
for(int k=1;k<=n;k++)
cout<<a[k]<<' ';
cout<<endl;
}
return;
}
for(int j=1;j<=n;j++)
{
if((!b[j])&&(!c[x+j])&&(!d[x-j+n]))
{
a[x]=j;
b[j]=1;
c[x+j]=1;
d[x-j+n]=1;
dfs(x+1);//深搜
//寻找每一个结果,进行回溯
b[j]=0;
c[x+j]=0;
d[x-j+n]=0;
}
}
}
int main()
{
cin>>n;
dfs(1);
cout<<total;
return 0;
}
洛谷–P1605 迷宫
// #include<bits/stdc++.h>
// using namespace std;
// int a[6][6];
// int tx,ty,sx,sy,fx,fy,t;
// int n,m,s;
// void dfs(int x,int y)//用x来表示x坐标,y来表示y坐标
// {
// if(x<1||x>n)//x坐标越界
// return;
// if(y<1||y>m)//y坐标越界
// return;
// if(x==fx&&y==fy)
// {
// s++;//终点站到了
// return;
// }
// if(a[x][y]==1||a[x][y]==2)//1代表走过了,2代表障碍
// return;
// a[x][y]=1;
// dfs(x+1,y);//下
// dfs(x,y+1);//右
// dfs(x-1,y);//上
// dfs(x,y-1);//左
// a[x][y]=0;//清零,目的是回溯
// }
// int main()
// {
// cin>>n>>m>>t;
// cin>>sx>>sy>>fx>>fy;
// for(int i=0;i<t;i++)
// {
// cin>>tx>>ty;
// a[tx][ty]=2;//标记障碍
// }
// if(a[fx][fy]==2)//如果终点有障碍
// {
// cout<<"0";//就没必要搜了
// return 0;//肯定搜不到
// }
// dfs(sx,sy);//从起点开始
// cout<<s;
// return 0;
// }
#include<bits/stdc++.h>
using namespace std;
int dr[4][2]={
{
0,1},{
0,-1},{
-1,0},{
1,0}};
const int N=1e3+10;
int b[N],a[N][N];
int n,m,T;
int ans;
int sx,sy,fx,fy;
void dfs(int x,int y)
{
if(x==fx && y==fy)
{
ans++; return;
}
for(int i=0;i<4;i++)
{
int xx=x+dr[i][0];
int yy=y+dr[i][1];
if(xx<=n && xx>=1 && yy>=1 && yy<=m && a[xx][yy]!=1)
{
a[xx][yy]=1;
dfs(xx,yy);
a[xx][yy]=0;
}
}
}
int main()
{
cin>>n>>m>>T;
cin>>sx>>sy>>fx>>fy;
for(int i=1,c,d;i<=T;i++)
{
cin>>c>>d;
a[c][d]=1;
}
a[sx][sy]=1;
dfs(sx,sy);
cout<<ans<<endl;
return 0;
}
洛谷–P1036 [NOIP2002 普及组] 选数
#include<bits/stdc++.h>
using namespace std;
int n,k,a[21],b[21],sum1=0;
bool isprime(int n1)
{
int n2=sqrt((double)n1);
for(int i=2;i<=n2;i++)
{
if(n1%i==0)
return false;
}
return true;
}
void dfs(int k1,int s)
{
if(k1>k)
{
int sum=0;
for(int i=1;i<=k;++i)
sum+=b[i];
if(isprime(sum))
sum1++;
return;
}
for(int i=s;i<=n;i++)
{
b[k1]=a[i];
dfs(k1+1,i+1);
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
dfs(1,1);
cout<<sum1;
return 0;
}