算法基础——搜索题目(持续更新)

BFS

Flood Fill

题单:

  1. 池塘计数

  2. 城堡问题

  3. 山峰和山谷

最短路

题单:

  1. 迷宫问题

  2. 武士风度的牛

  3. 抓住那头牛

多源BFS

题单:

  1. 矩阵距离:初始队首元素不只有一个

最小步数模型

题单:

  1. 魔板

双端队列

题单:

  1. 电路维修
#include<bits/stdc++.h>

using namespace std;
#define x first
#define y second

typedef pair<int,int> PII;
const int N=510;
int r,c;
char g[N][N];
int dist[N][N];

int bfs(){
    char move[]="\\/\\/";
    int mx[]={-1,-1,1,1};
    int my[]={-1,1,1,-1};
    int ix[]={-1,-1,0,0};
    int iy[]={-1,0,0,-1};
    
    memset(dist,0x3f,sizeof dist);
    dist[0][0]=0;
    deque<PII> q;
    q.push_front({0,0});
    
    while(q.size()){
        auto t=q.front();
        q.pop_front();
        
        if(t.x==r&&t.y==c) return dist[r][c];
        
        for(int i=0;i<4;i++){
            int ax=t.x+mx[i];
            int ay=t.y+my[i];
            int bx=t.x+ix[i];
            int by=t.y+iy[i];
            
            if(ax<0||ax>r||ay<0||ay>c) continue;
            
            int w=g[bx][by]!=move[i];
            int d=dist[t.x][t.y]+w;
            if(d<dist[ax][ay]){
                dist[ax][ay]=d;
                if(!w) q.push_front({ax,ay});
                else q.push_back({ax,ay});
            }
        }
    }
    return -1;
}

signed main(){
    int t;
    cin>>t;
    while(t--){
        cin>>r>>c;
        
        //优化1
        //if(r+c & 1 ){
        //    puts("NO SOLUTION");
        //    continue;
        //}
        
        for(int i=0;i<r;i++) cin>>g[i];
        int res=bfs();
        if(res==-1) puts("NO SOLUTION"); //(1)
        else cout<<res<<endl;
    }
    return 0;
}

双向广搜

题单:

  1. 字串变换
// 采用单向bfs搜索
// 数据一旦加强就过不了

# include<bits/stdc++.h>

using namespace std;
string A,B;
const int N=21;
vector<string> a(N),b(N);
int n;

int bfs(){
    unordered_map<string,int> d;
    queue<string> q;
    q.push(A);
    while(q.size()){
        string t = q.front();
        q.pop();
        
        if(t==B) return d[t];
        
        for(int i = 0; i < t.size(); i++){
            for(int j=0; j < n; j ++){
                if(t.substr(i,a[j].size()) == a[j]){
                    string sub=t.substr(0,i)+b[j]+t.substr(i+a[j].size());
                    if(!d.count(sub)){
                        d[sub]=d[t]+1;
                        q.push(sub);
                    }
                }
            }
        }
    }
    
    return -1;
}

signed main(){
    
    cin>>A>>B;
    while(cin>>a[n]>>b[n++]);
    int t=bfs();
    if(t!=-1) cout<<t<<endl;
    else puts("NO ANSWER!");
    
    
    return 0;
}
// 采用双向bfs搜索
// y总版
# include<bits/stdc++.h>

using namespace std;
string A,B;
const int N=21;
vector<string> a(N),b(N);
unordered_map<string,int> da,db;
int n;

int extend(queue<string>& q, unordered_map<string,int> &da,unordered_map<string,int> &db,vector<string> &a,vector<string> &b){
    
    int d = da[q.front()];
    
    while(q.size()&&da[q.front()]==d){
        string t = q.front();
        q.pop();
        for(int i=0;i<t.size();i++){
            for(int j=0;j<n;j++){
                if(t.substr(i,a[j].size())==a[j]){
                    string sub = t.substr(0,i)+b[j]+t.substr(i+a[j].size());
                    if(db.count(sub)) return db[sub]+da[t]+1;
                    if(!da.count(sub)){
                        q.push(sub);
                        da[sub]=da[t]+1;
                    }
                }
            }
        }
        
    }
    return 11;
}

int bfs(){
    if(A==B) return 0;
    queue<string> qa,qb;
    unordered_map<string,int> da,db;
    qa.push(A);
    qb.push(B);
    da[A]=0,db[B]=0;
    int step=0;
    while(qa.size()&&qb.size()){
        int t;
        if(qa.size()>qb.size()){
            t=extend(qb,db,da,b,a);
        }
        else{
            t=extend(qa,da,db,a,b);
        }
        if(t<=10) return t;
        if(++step==10) return -1;
    }
    
    return -1;
}

signed main(){
    
    cin>>A>>B;
    while(cin>>a[n]>>b[n++]);
    int t=bfs();
    if(t!=-1) cout<<t<<endl;
    else puts("NO ANSWER!");
    
    
    return 0;
}
// 采用单向bfs搜索
# include<bits/stdc++.h>

using namespace std;
string A,B;
const int N=21;
vector<string> a(N),b(N);
unordered_map<string,int> da,db;
int n;

int extend(queue<string>& q, unordered_map<string,int> &da,unordered_map<string,int> &db,vector<string> &a,vector<string> &b){
    
    int d = da[q.front()];
    
    while(q.size()&&da[q.front()]==d){
        string t = q.front();
        q.pop();
        if(da[t]==d){
            for(int i=0;i<t.size();i++){
                for(int j=0;j<n;j++){
                    if(t.substr(i,a[j].size())==a[j]){
                        string sub = t.substr(0,i)+b[j]+t.substr(i+a[j].size());
                        if(db.count(sub)) return db[sub]+da[t]+1;
                        if(!da.count(sub)){
                            q.push(sub);
                            da[sub]=da[t]+1;
                        }
                    }
                }
            }
        }
        else break;
        
    }
    return 11;
}

int bfs(){
    if(A==B) return 0;
    queue<string> qa,qb;
    unordered_map<string,int> da,db;
    qa.push(A);
    qb.push(B);
    da[A]=0,db[B]=0;
    int step=0;
    while(qa.size()&&qb.size()){
        int t;
        if(qa.size()>qb.size()){
            t=extend(qb,db,da,b,a);
        }
        else{
            t=extend(qa,da,db,a,b);
        }
        if(t<=10) return t;
        if(++step==10) return -1;
    }
    
    return -1;
}

signed main(){
    
    cin>>A>>B;
    while(cin>>a[n]>>b[n++]);
    int t=bfs();
    if(t!=-1) cout<<t<<endl;
    else puts("NO ANSWER!");
    
    
    return 0;
}

A*

题单:

  1. 第K短路

  2. 八数码:

    在基础课的基础上需要知道记录每一步的操作,可通过记录上一次的状态推得

DFS

DFS之搜索顺序

  1. 分成互质组

优秀题解

#include<iostream>

using namespace std;
const int N=11;
int ans=N; //记录最优解,求最小因此初始化为最大
int n;
int a[N],st[N];
int ga[N][N]; //存储每组的元素

int gcd(int x,int y){
    return y?gcd(y,x%y):x;
}

bool check(int g,int gr,int x){
    for(int i=0;i<gr;i++){
        if(gcd(ga[g][i],x)>1) return false;
    }
    return true;
}

//g表示当前是第几组,gr表示当前组的元素个数
//start表示从a数组的哪一个位置开始找放入组内的数,
//从而确定每个数是否需要开新的组,可以恒为零
//
bool dfs(int g,int gr,int start,int tot){ 
    if(g>=ans) return 0;
    if(tot==n) ans=g;
    
    int flag = 1;
    //如果i从0开始就会死循环,
    //不确定是不是因为时间限制,
    //不知道有没有死循环
    for(int i=start;i<n;i++){
        if(!st[i]&&check(g,gr,a[i])){
            st[i]=1;
            ga[g][gr]=a[i];
            dfs(g,gr+1,start+1,tot+1);
            st[i]=0;    //恢复st[i]是考虑第i个数放在不同组的情况
            flag=0;
        }
    }
    //只要新开一组就start=0开始找可以放进新组中的数
    //这些数包括回溯恢复的一些数,因为当它们在不同组时,
    //和不同的数组成的团可能让新开组的数的后一个数放进去,
    //体现在同级的循环上;
    if(flag) dfs(g+1,0,0,tot);
}

signed main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    dfs(1,0,0,0);
    cout<<ans<<endl;
    return 0;
}

DFS之剪枝

  1. 小猫爬山

排序找最小分支

方案数大于最大数剪枝

枚举小猫,考虑开新车放小猫

#include<bits/stdc++.h>

using namespace std;
const int N=18;
int n,m;
int a[N],sum[N];
int ans = N;

void dfs(int u,int k){
    if(k>=ans) return;
    
    if(u==n){   //当枚举完小猫之后,赋k值
        ans=k;
        return ;
    }
    
    for(int i=0;i<k;i++){
        if(sum[i]+a[u]<=m){
            sum[i]+=a[u];
            dfs(u+1,k);
            sum[i]-=a[u];
        }
    }
    
    sum[k]=a[u];
    dfs(u+1,k+1);
    sum[k]=0;
}

signed main(){
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    sort(a,a+n);
    reverse(a,a+n);
    
    dfs(0,0);
    cout<<ans<<endl;
    return 0;
}
  1. 数独

位运算+dfs

#include<bits/stdc++.h>

using namespace std;
const int N=9,M=1<<N;
int col[N],row[N],g[3][3];
int ones[M],lg[M];
char s[100];

void init(){
    for(int i=0;i<N;i++){
        col[i] = (1<<N) - 1;    //不加括号的位运算不能得到结果
        row[i] = (1<<N) - 1;
    }
    
    for(int i=0;i<3; i++){
        for(int j=0 ;j < 3 ; j++){
            g[i][j] = (1<<N) - 1;
        }
    }
}

int lowbit(int x){
    return x&-x;
}

void draw(int x,int y,int t,bool flag){
    
    if(flag){
        s[x*N+y] = '1'+t;
    }
    else{
        s[x*N+y] = '.';
    }
    
    int v=1<<t;
    if(!flag) v=-v;
    
    row[x] -= v;
    col[y] -= v;
    g[x/3][y/3] -= v;
    
}

int get(int x,int y){
    return row[x]&col[y]&g[x/3][y/3];
}

bool dfs(int cnt){
    if(!cnt) return true;
    
    int minv=10;
    int x,y;
    
    for(int i = 0; i < N ; i++){
        for(int j=0; j < N ; j++){
            if(s[i*N + j]=='.'){
                int v = get(i,j);
                if(ones[v]<minv){
                    minv= ones[v];
                    x=i,y=j;
                }
            }
        }
    }
    
    int v = get(x,y);
    for(int i=v;i;i-=lowbit(i)){
        int t = lg[lowbit(i)];
        draw(x,y,t,true);
        if(dfs(cnt-1)) return true;
        draw(x,y,t,false);
    }
    return false;
}



signed main(){
    
    for(int i = 0;i<1<<N;i++){
        for(int j=0;j<N ; j++){
            ones[i]+=((i>>j) & 1);
        }
    }
    
    
    
    for(int i=0;i<N ;i++) lg[1<<i] = i;
    
    while(cin>>s,s[0]!='e'){
        init();
        int cnt=0;
        for(int i=0,k=0;i<N;i++){
            for(int j=0;j<N;j++,k++){
                if(s[k]=='.'){
                    cnt++;
                }
                else{
                    int t=s[k]-'1'; 
                    draw(i,j,t,true);
                }
            }
        }
        dfs(cnt);
        puts(s);
    }
    return 0;
}
  1. 木棒

二分木棍最小值,向左找,dfs找到可以满足等长的总共木棒数,枚举木棒,将木棍放入,但其实木棍最长也就64,不会爆int,所以从1开始枚举就好了

#include<bits/stdc++.h>

using namespace std;
const int N=70;
int n;
int a[N],v[N];
int sum,length;

//枚举木棒
bool dfs(int u,int cur,int start){
  if((u)*length==sum) return true;
  if(cur==length) return dfs(u+1,0,0);
  
  for(int i=start;i<n;i++){
    if(!v[i]&&cur+a[i]<=length){
      v[i]=1;
      if(dfs(u,cur+a[i],i+1)) return true;
      v[i]=0;
      
      if(!cur||cur+a[i]==length) return false;
      
      int j=i;
      while(j<n&&a[i]==a[j]) j++;
      i=j-1;
    }
  }
  return false;
}



signed main(){
  while(cin>>n,n!=0){
    length = 1;
    sum=0;
    memset(v,0,sizeof v);
    for(int i=0;i<n;i++){
      cin>>a[i];
      sum+=a[i];
    }
    
    sort(a, a + n);
    reverse(a, a + n);
    
    while(true){
      if(sum%length==0&&dfs(0,0,0)){
        cout<<length<<endl;
        break;
      }
      length++;
    }
  }
  return 0;
}
  1. 生日蛋糕

DFS之迭代加深

  1. 加成序列

双向DFS

  1. 送礼物

IDA*

  1. 排书

  2. 回转游戏

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值