搜索专题(未完)
搜索做题总结
前言:
因为搜索一直被众OIer称为万能算法——很多题都能用搜索得部分分,所以...所以...嗯,还是重新再刷一遍搜索的题,找找感觉吧!希望在之后的大小比赛考试中能够发挥出来quq
搜索提单——从基础到提高(未完):
- 基础
-- 洛谷P1141 01迷宫
-- 洛谷P1683 入门 (此“入门”非彼“入门”,虽然都还挺简单的)
-- 洛谷P1036 选数
-- 洛谷P1443 马的遍历
(题目有点长..我这个蒟蒻读了两遍题才读懂QAQ但是题很简单)
其实这些题很多都是有相似的地方的,而这些相似的地方就是搜索的基础。我们可以把这里作为突破口,然后清晰思路,更利于编程。
常见的搜索基础类型:“搜索求联通块”、“n个数选k个数”
- 提高
-- 洛谷P2360 地下城主
(虽然标签是普及-,但是我认为比马的遍历那些题会难一点?大概还是因为我蒻)
-- 洛谷P1434 滑雪
-- 洛谷P1019 单词接龙
-- 洛谷P1032 字串变换
-- 洛谷P3956 棋盘
(这道题我用广搜没有搞出来,就是太菜,然后使用了WS同学的深搜,这里就推荐一篇他的题解:棋盘 题解)
-- 洛谷P1118 [USACO06FEB]Backward Digit Sums G/S
部分题目思路:
- 基础
-- 求细胞个数、01迷宫、入门、yyy2015c01挑战算周长:“搜索求联通块”
-- 组合的输出、选数:DFS,“n个数选k个数”
-- 马的遍历、离开中山路:BFS求最短距离
- 提高
-- 地下城主:三维搜索+求最短距离,注意一下数组是先层再行再列(我栽在这1hQAQ),后面给出该题的代码
-- Mzc和男家丁的游戏、血色先锋队:求最短距离
-- 滑雪、单词接龙、字串变换、棋盘、Backward Digit Sums G/S:之后会给出代码&题解
部分题目代码(题解以后再补充qwq):
- 求细胞个数
#include <bits/stdc++.h>
using namespace std;
int n,m,ans;
char a[105][105];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
inline void bfs(int x,int y) {
a[x][y]='0';
for(register int i=0;i<4;i++) {
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>n||xx<1||yy>m||yy<1||a[xx][yy]=='0') continue;
bfs(xx,yy);
}
}
int main() {
scanf("%d%d",&n,&m);
for(register int i=1;i<=n;i++) {
for(register int j=1;j<=m;j++) {
cin>>a[i][j];
}
}
for(register int i=1;i<=n;i++) {
for(register int j=1;j<=m;j++) {
if(a[i][j]!='0') {
ans++;
bfs(i,j);
}
}
}
printf("%d",ans);
return 0;
}
- 选数
#include <bits/stdc++.h>
using namespace std;
int n,r,sum,ans,num[5000001];
inline bool check(int tot) {
for(register int i=2;i*i<=tot;i++) {
if(tot%i==0) return false;
}
return true;
}
inline void dfs(int now,int k) {
for(register int i=k;i<=n;i++) {
sum+=num[i];
if(now==r) {
if(check(sum)) ans++;
}
else dfs(now+1,i+1);
sum-=num[i];
}
}
int main() {
scanf("%d%d",&n,&r);
for(register int i=1;i<=n;i++) {
scanf("%d",&num[i]);
}
dfs(1,1);
printf("%d",ans);
return 0;
}
- 马的遍历
#include <bits/stdc++.h>
using namespace std;
int n,m,sx,sy,pd[4005][4005],ans[4005][4005];
int dx[8]={1,2,2,1,-1,-2,-2,-1};
int dy[8]={2,1,-1,-2,-2,-1,1,2};
struct node {
int x,y,st;
} q[160005];
inline void bfs(int xx,int yy) {
pd[xx][yy]=1;
int front=1,tail=1;
q[front].x=xx;
q[front].y=yy;
q[front].st=0;
while(front<=tail) {
for(register int i=0;i<8;i++) {
int xs=q[front].x+dx[i];
int ys=q[front].y+dy[i];
if(xs>=1&&xs<=n&&ys>=1&&ys<=m&&pd[xs][ys]==0) {
tail++;
q[tail].x=xs;
q[tail].y=ys;
q[tail].st=q[front].st+1;
ans[xs][ys]=q[tail].st;
pd[xs][ys]=1;
}
}
front++;
}
}
int main() {
memset(ans,-1,sizeof(ans));
scanf("%d%d%d%d",&n,&m,&sx,&sy);
ans[sx][sy]=0;
bfs(sx,sy);
for(register int i=1;i<=n;i++) {
for(register int j=1;j<=m;j++) {
printf("%-5d",ans[i][j]);
}
puts("");
}
return 0;
}
- 地下城主
#include <bits/stdc++.h>
using namespace std;
int L,R,C,sx,sy,sh,ex,ey,eh,sum,ans;
char a[31][31][31];
int dx[6]={0,1,0,-1,0,0};
int dy[6]={1,0,-1,0,0,0};
int dh[6]={0,0,0,0,1,-1};
struct node {
int x,y,h,st;
} q[100001];
inline void bfs(int xx,int yy,int hh) {
a[hh][xx][yy]='#'; //一定要注意先层再行再列!
int front=1,tail=1;
q[front].x=xx;
q[front].y=yy;
q[front].h=hh;
q[front].st=0;
while(front<=tail) {
for(register int i=0;i<6;i++) {
int xs=q[front].x+dx[i];
int ys=q[front].y+dy[i];
int hs=q[front].h+dh[i];
if(xs>=1&&xs<=R&&ys>=1&&ys<=C&&hs>=1&&hs<=L&&a[hs][xs][ys]!='#') {
tail++;
q[tail].x=xs;
q[tail].y=ys;
q[tail].h=hs;
q[tail].st=q[front].st+1;
if(xs==ex&&ys==ey&&hs==eh) {
printf("Escaped in %d minute(s).",q[tail].st);
return ;
}
a[hs][xs][ys]='#';
}
}
front++;
}
puts("Trapped!");
}
int main() {
scanf("%d%d%d",&L,&R,&C);
for(register int i=1;i<=L;i++) {
for(register int j=1;j<=R;j++) {
for(register int k=1;k<=C;k++) {
cin>>a[i][j][k];
if(a[i][j][k]=='S') {
sx=j;
sy=k;
sh=i;
}
if(a[i][j][k]=='E') {
ex=j;
ey=k;
eh=i;
}
}
}
}
bfs(sx,sy,sh);
return 0;
}
- 血色先锋队
#include <bits/stdc++.h>
using namespace std;
int n,m,a,b,pd[5005][5005],ans[5005][5005];
int x,y;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
struct node {
int x,y,st;
}q[2500005];
inline void bfs(int tot) {
int front=1,tail=tot;
while(front<=tail) {
for(register int i=0;i<4;i++) {
int xx=q[front].x+dx[i];
int yy=q[front].y+dy[i];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&pd[xx][yy]==0) {
pd[xx][yy]=1;
tail++;
q[tail].x=xx;
q[tail].y=yy;
q[tail].st=q[front].st+1;
ans[xx][yy]=q[tail].st;
}
}
front++;
}
}
int main() {
scanf("%d%d%d%d",&n,&m,&a,&b);
for(register int i=1;i<=a;i++) {
scanf("%d%d",&x,&y);
q[i].x=x;
q[i].y=y;
q[i].st=0;
pd[x][y]=1;
ans[x][y]=0;
}
bfs(a);
for(register int i=1;i<=b;i++) {
scanf("%d%d",&x,&y);
printf("%d\n",ans[x][y]);
}
return 0;
}
- 滑雪
#include <bits/stdc++.h>
using namespace std;
int c,r,sum=0,a[101][101],f[101][101];
int dx[5]={0,0,-1,0,1};
int dy[5]={0,1,0,-1,0};
inline void dfs(int x,int y) {
f[x][y]=1;
int tot=0,ans=1;
for(int i=1;i<=4;i++) {
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>=1&&xx<=r&&yy>=1&&yy<=c&&a[xx][yy]>a[x][y]) {
if(f[xx][yy]==0) {
dfs(xx,yy);
}
f[x][y]=max(f[x][y],f[xx][yy]+1);
}
}
}
int main() {
cin>>r>>c;
for(int i=1;i<=r;i++) {
for(int j=1;j<=c;j++) {
cin>>a[i][j];
}
}
for(int i=1;i<=r;i++) {
for(int j=1;j<=c;j++) {
if(f[i][j]==0) dfs(i,j);
sum=max(sum,f[i][j]);
}
}
cout<<sum;
return 0;
}
这道题我们用字母来模拟一下自上而下的合并过程,然后...你就会发现和某某三角(杨辉三角啦)有那么一点点的像,模拟如下:
先来看看n=4的情况
a b c d
a+b b+c c+d
a+2b+c b+2c+d
a+3b+3c+d(sum)
再来看看n=6的情况
a b c d e f
a+b b+c c+d d+e e+f
a+2b+c b+2c+d c+2d+e d+2e+f
a+3b+3c+d b+3c+3d+e c+3d+3e+f
a+4b+6c+4d+e b+4c+6d+4e+f
a+5b+10c+10d+5e+f(sum)
然后我们来看看某某三角
【1】1
【2】1 1
【3】1 2 1
【4】1 3 3 1
【5】1 4 6 4 1
【6】1 5 10 10 5 1
······
将两者进行对比,我们就会发现:
sum表达式中各个项的系数就是杨辉三角中第n行的数字!
#include <bits/stdc++.h>
using namespace std;
int n,sum,yh[21][21],a[200010],flag[200010];
inline void dfs(int k,int now) {
if(now>sum) return ; //剪枝,如果当前数字和已经大于sum,直接退出
if(k>n&&now==sum) {
for(register int i=1;i<=n;i++) printf("%d ",a[i]);
exit(0); //找到了就直接结束程序
}
for(register int i=1;i<=n;i++) {
if(flag[i]==0) { //判重
a[k]=i; //存数
flag[i]=1;
dfs(k+1,now+i*yh[n][k]); //核心!
flag[i]=0;
}
}
}
int main() {
scanf("%d%d",&n,&sum);
yh[1][1]=1;
for(register int i=2;i<=n;i++) { //预处理杨辉三角
for(register int j=1;j<=i;j++) {
yh[i][j]=yh[i-1][j]+yh[i-1][j-1];
}
}
/*for(register int i=1;i<=n;i++) { 打印杨辉三角
for(register int j=1;j<=i;j++) {
cout<<yh[i][j]<<" ";
}
cout<<endl;
}*/
dfs(1,0);
return 0;
}