【kuangbin带我飞】专题一 简单搜索

本文深入探讨了深度优先搜索(DFS)和广度优先搜索(BFS)在解决复杂问题中的应用,包括棋盘问题、迷宫求解、油井探测等场景,提供了详细的代码实现和技巧分享。

A-棋盘问题 dfs

1.dfs进入时打上标记,退出时清除,不需要额外的状态记录

2.可行性剪枝,减小常数

3.用r[i],c[j]表示行和列的占用情况,减小常数

#include<bits/stdc++.h>
using namespace std;

int n,k;
char g[10][10];
int r[10],c[10];

int top,ans;
pair<int,int> id[10];         //第i个空位的坐标

inline bool ok(int i,int j){
    if(r[i]==0&&c[j]==0)
        return 1;
    return 0;
}

void dfs(int idx,int pl,int res){
    //printf("idx=%d pl=%d res=%d\n",idx,pl,res);
    if(idx==top){
        if(pl==0&&res==0){
            ans++;

            /*for(int i=0;i<n;i++){
                 for(int j=0;j<n;j++){
                    printf("%c",g[i][j]);
                 }
                 printf("\n");
            }

            printf("ans++\n");*/

        }
        return;
    }

    if(top-idx<res){
        //可行性剪枝
        //即使后面的都放也没办法放完
        return;
    }

    if(pl==1){
        if(res==0)
            return;
        /*for(int i=0;i<n;i++){
            if(g[i][id[idx].second]=='$')
                return;
        }
        for(int j=0;j<n;j++){
            if(g[id[idx].first][j]=='$')
                return;
        }*/
        if(ok(id[idx].first,id[idx].second)){
            //g[id[idx].first][id[idx].second]='$';
            r[id[idx].first]=1;
            c[id[idx].second]=1;
            dfs(idx+1,0,res-1);
            dfs(idx+1,1,res-1);
            //g[id[idx].first][id[idx].second]='#';
            r[id[idx].first]=0;
            c[id[idx].second]=0;
        }
        else{
            return;
        }
    }
    else{
        dfs(idx+1,0,res);
        dfs(idx+1,1,res);
    }

}

int main(){
    while(1){
        scanf("%d%d",&n,&k);
        if(n==-1)
            break;

        for(int i=0;i<n;i++){
            scanf("%s",g[i]);
            r[i]=0;
            c[i]=0;
        }

        top=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(g[i][j]=='#'){
                    id[top++]={i,j};
                }
            }
        }

        ans=0;
        if(k){
            dfs(0,0,k);
            dfs(0,1,k);
        }
        printf("%d\n",ans);
    }
}

B - Dungeon Master bfs

第一次不看书写bfs,犯了一些错误

1.写成了dfs,妄想递归调用自己(应该在循环里解决整个bfs过程)

2.某个格子入队后没有加上标记,导致其重复入队(一个节点应分为:0-未访问,1-已出队,2-已入队)

3.写法非常难看

4.队列没有clear()方法,只能一个一个弹出

#include<bits/stdc++.h>
using namespace std;

int L,R,C;
char g[32][32][32];
int vis[32][32][32];

struct cor{
    int l,r,c,m;
    cor(int ll=0,int rr=0,int cc=0,int mm=0){
        l=ll,r=rr,c=cc;
        m=mm;
    }
};

int ans;
queue<cor> Q;

bool inRange(int l,int r,int c,int m){
    if(l<0||l>=L||r<0||r>=R||c<0||c>=C)
        return 0;
    if(g[l][r][c]=='#')
        return 0;
    if(vis[l][r][c]!=0)
        return 0;
    vis[l][r][c]=2;
    Q.push(cor(l,r,c,m));
    return 1;
}

void bfs(int l,int r,int c,int m){
    if(ans!=-1)
        return;
    if(l<0||l>=L||r<0||r>=R||c<0||c>=C)
        return;
    if(vis[l][r][c]!=0)
        return;
    if(g[l][r][c]=='E'){
        ans=m;
        return;
    }
    if(g[l][r][c]=='#')
        return;

    Q.push(cor(l,r,c));
    while(!Q.empty()){
        cor c1=Q.front();
        vis[c1.l][c1.r][c1.c]=1;
        if(g[c1.l][c1.r][c1.c]=='E'){
            ans=c1.m;
            return;
        }
        Q.pop();
        inRange(c1.l-1,c1.r,c1.c,c1.m+1);
        inRange(c1.l-1,c1.r,c1.c,c1.m+1);
        inRange(c1.l+1,c1.r,c1.c,c1.m+1);
        inRange(c1.l,c1.r-1,c1.c,c1.m+1);
        inRange(c1.l,c1.r+1,c1.c,c1.m+1);
        inRange(c1.l,c1.r,c1.c-1,c1.m+1);
        inRange(c1.l,c1.r,c1.c+1,c1.m+1);
    }

}

int main(){
    while(1){
        scanf("%d%d%d",&L,&R,&C);

        if(L==0)
            break;

        while(!Q.empty())
            Q.pop();
        memset(vis,0,sizeof(vis));

        for(int l=0;l<L;l++){
            for(int r=0;r<R;r++){
                scanf("%s",g[l][r]);
            }
        }

        ans=-1;
        for(int l=0;l<L;l++){
            for(int r=0;r<R;r++){
                for(int c=0;c<C;c++){
                    if(g[l][r][c]=='S'){
                        bfs(l,r,c,0);
                        break;
                    }
                }
            }
        }
        if(ans>=0){
            printf("Escaped in %d minute(s).\n",ans);
        }
        else{
            puts("Trapped!");
        }
    }
}

修改得好看一点,改成一个enqueue()函数,在enqueue()函数里判断越界、重复和搜索完成。dequeue()函数则不是很有用。

#include<bits/stdc++.h>
using namespace std;

int L,R,C;
char g[32][32][32];
int vis[32][32][32];

struct cor{
    int l,r,c,m;
    cor(int ll=0,int rr=0,int cc=0,int mm=0){
        l=ll,r=rr,c=cc;
        m=mm;
    }
};

int ans;
queue<cor> Q;

inline bool enqueue(int l,int r,int c,int m){
    if(ans!=-1){
        return 1;
    }
    if(l<0||l>=L||r<0||r>=R||c<0||c>=C)
        return 0;
    if(g[l][r][c]=='#')
        return 0;
    if(vis[l][r][c]!=0)
        return 0;
    vis[l][r][c]=2;
    if(g[l][r][c]=='E'){
        ans=m;
        return 1;
    }
    Q.push(cor(l,r,c,m));
    return 1;
}

inline bool dequeue(){
    if(Q.empty())
        return 0;
    else{
        cor c1=Q.front();
        vis[c1.l][c1.r][c1.c]=1;
        Q.pop();
    }

}

void bfs(){
    while(!Q.empty()){
        cor c1=Q.front();
        dequeue();

        enqueue(c1.l-1,c1.r,c1.c,c1.m+1);
        enqueue(c1.l-1,c1.r,c1.c,c1.m+1);
        enqueue(c1.l+1,c1.r,c1.c,c1.m+1);
        enqueue(c1.l,c1.r-1,c1.c,c1.m+1);
        enqueue(c1.l,c1.r+1,c1.c,c1.m+1);
        enqueue(c1.l,c1.r,c1.c-1,c1.m+1);
        enqueue(c1.l,c1.r,c1.c+1,c1.m+1);
        if(ans!=-1)
            return;
    }

}

int main(){
    while(1){
        scanf("%d%d%d",&L,&R,&C);

        if(L==0)
            break;

        while(!Q.empty())
            Q.pop();
        memset(vis,0,sizeof(vis));

        for(int l=0;l<L;l++){
            for(int r=0;r<R;r++){
                scanf("%s",g[l][r]);
            }
        }

        ans=-1;
        for(int l=0;l<L;l++){
            for(int r=0;r<R;r++){
                for(int c=0;c<C;c++){
                    if(g[l][r][c]=='S'){
                        Q.push(cor(l,r,c,0));
                        break;
                    }
                }
            }
        }

        bfs();

        if(ans>=0){
            printf("Escaped in %d minute(s).\n",ans);
        }
        else{
            puts("Trapped!");
        }
    }
}

C - Catch That Cow

看上去就是bfs瞎改一下的样子,不知道对不对。(有点像今天看的机器人炸城市的dijkstra算法,瞎改一下)

#include<bits/stdc++.h>
using namespace std;

int n,k;
int vis[200005];

struct cor{
    int x;
    int t;
    cor(int xx=0,int tt=0){
        x=xx,t=tt;
    }
};
queue<cor> Q;

void enqueue(int x,int t){
    if(x<0||x>200000){
        return;
    }
    if(vis[x]!=-1)
        return;
    vis[x]=t;
    Q.push(cor(x,t));
}

void bfs(){
    vis[n]=0;
    Q.push(cor(n,0));
    while(!Q.empty()){
        cor c=Q.front();
        int x=c.x;
        int t=c.t;
        Q.pop();
        enqueue(x-1,t+1);
        enqueue(x+1,t+1);
        enqueue(2*x,t+1);
    }
}

int main(){
    while(~scanf("%d%d",&n,&k)){
        memset(vis,-1,sizeof(vis));
        bfs();
        printf("%d\n",vis[k]);
    }
}

 

D

E - Find The Multiple 各种搜索

dfs发现198会T,尝试改成bfs没想到爆了ll,改成string效率感人但是还是交了一发,果然T了。怒打表。

打表发现最长的198也是19位长度,在ull的范围内(但是爆ll)。被题面欺诈了,北大果然喜欢题面欺诈(某jls)。难道真的只能先打表吗?已经知道ull不会爆之后尝试的ull写法。也是T了(估计是取模次数太多),连清空队列的时间都不够。下面是重定向到表再复制进来。注释里的是正解。意思是不打表就不会知道ull不会爆?太坑爹了。我都把表打出来了不是乱搞就可以过吗?

#include<bits/stdc++.h>
using namespace std;
#define ll long long
/*
int n;
string ans;
int maxn;

struct num{
    string d;
    int re;
    num();
    num(string dd,int ree){
        d=dd;
        re=ree;
    }
};
queue<num> Q;

void bfs(){
    Q.push(num("",0));
    while(!Q.empty()){
        string s=Q.front().d;
        //cout<<s<<endl;
        int re=Q.front().re;
        int l=s.length();
        int r=1;
        for(int i=0;i<l;i++){
            r*=10;
            r%=n;
        }
        int re2=(re+r)%n;
        if(re2==0){
            ans='1'+s;
            return;
        }
        Q.pop();
        Q.push(num(string('0'+s),re));
        Q.push(num(string('1'+s),re2));
    }
}

int main(){
    freopen("E.out","w",stdout);
    for(int i=1;i<=200;i++){
        n=i;
        if(n==0)
            break;

        ans="";
        while(!Q.empty()){
            Q.pop();
        }

        bfs();
        cout<<"\""<<ans<<"\",";
    }
}
*/

string ans[]={"1","10","111","100","10","1110","1001","1000","111111111","10","11","11100","1001",
"10010","1110","10000","11101","1111111110","11001","100","10101","110","110101",
"111000","100","10010","1111111101","100100","1101101","1110","111011","100000",
"111111","111010","10010","11111111100","111","110010","10101","1000","11111",
"101010","1101101","1100","1111111110","1101010","10011","1110000","1100001","100",
"100011","100100","100011","11111111010","110","1001000","11001","11011010",
"11011111","11100","100101","1110110","1111011111","1000000","10010","1111110",
"1101011","1110100","11111001","10010","10011","111111111000","10001","1110","11100",
"1100100","1001","101010","11101001","10000","1111111101","111110","101011",
"1010100","111010","11011010","11010111","11000","11010101","1111111110","1001",
"11010100","10000011","100110","110010","11100000","11100001","11000010",
"111111111111111111","100","101","1000110","11100001","1001000","101010","1000110",
"100010011","111111110100","1111111011","110","111","10010000","1011011","110010",
"1101010","110110100","11111110101","110111110","110001101","111000","11011",
"1001010","10011100011","11101100","1000","11110111110","11010011","10000000",
"100100001","10010","101001","11111100","11101111","11010110","11111111010",
"11101000","10001","111110010","110110101","100100","10011","100110","1001",
"1111111110000","11011010","100010","1100001","11100","110111","11100","1110001",
"11001000","11111011011","10010","1110110","1010100","10101101011","111010010",
"100011","100000","11101111","11111111010","1010111","1111100","1111110","1010110",
"11111011","10101000","10111101","111010","1111011111","110110100","1011001101",
"110101110","100100","110000","101110011","110101010","11010111","11111111100",
"1001111","10010","100101","110101000","1110","100000110","1001011","1001100",
"1111111100001","110010","11101111","111000000","11001","111000010","101010",
"110000100","1101000101","1111111111111111110","111000011","1000"};

int main(){
    int n;
    while(cin>>n,n){
        cout<<ans[n-1]<<endl;
    }
}

F - Prime Path

居然把“只有一位数字不同”写成了两个数的差是1~9,10~90,100~900,1000~9000,有毒。然后还交了一发TLE因为是while的t和后面的t重名了,说明以后T组数据还是写大写的T吧。把邻接矩阵改成邻接向量并搜索到答案就退出,时间从235ms优化到79ms,说明影响还是很大的,改成双向广搜会不会更快?(写了一个不判Impossible的居然过了???)

#include<bits/stdc++.h>
using namespace std;
#define ll long long


int prime[10000];
int top=0;

vector<int> g[1100];
int vis[1100]={};
int p[1100]={};

bool isPrime(int p){
    int cei=(sqrt(double(p)));
    for(int i=2;i<=cei;i++){
        if(p%i==0){
            return 0;
        }
    }
    return 1;
}

int a[4];

void init(){
    for(int i=1000;i<=9999;i++){
        int p=i;
        if(isPrime(p)){
            prime[top++]=p;
        }
        else{
            ;
        }
    }

    //cout<<top<<endl;
    for(int i=0;i<top;i++){
        for(int j=i+1;j<top;j++){
            int l1=prime[j]%10==prime[i]%10;
            int l2=prime[j]/10%10==prime[i]/10%10;
            int l3=prime[j]/100%10==prime[i]/100%10;
            int l4=prime[j]/1000%10==prime[i]/1000%10;
            if(l1&&l2&&l3||l1&&l2&&l4||l1&&l4&&l3||l4&&l2&&l3){
                //if(prime[i]==1009||prime[j]==1009)
                //cout<<prime[i]<<" "<<prime[j]<<endl;
                g[i].push_back(j);
                g[j].push_back(i);
            }
        }
    }

}


int s,t;
int sid,tid;

queue<int> Q;
void bfs(){
    vis[sid]=0;
    Q.push(sid);
    int suc=0;
    while(!Q.empty()){
        int id=Q.front();
        //cout<<prime[id]<<" "<<vis[id]<<" "<<p[id]<<endl;
        Q.pop();

        int l=g[id].size();
        for(int i=0;i<l;i++){
            if(vis[g[id][i]]==-1){

                vis[g[id][i]]=vis[id]+1;
                if(g[id][i]==tid){
                    suc=1;
                    break;
                }
                p[g[id][i]]=prime[id];
                Q.push(g[id][i]);
            }
            if(suc==1){
                break;
            }
        }
    }
     while(!Q.empty()){
        Q.pop();
     }
}


int main(){
    init();
    int T;
    while(~scanf("%d",&T)){
        for(int i=0;i<T;i++){
            scanf("%d%d",&s,&t);

            memset(vis,-1,sizeof(vis));
            sid=lower_bound(prime,prime+top,s)-prime;
            tid=lower_bound(prime,prime+top,t)-prime;
            bfs();

            //printf("p=%d ",prime[tid]);
            if(vis[tid]!=-1)
                printf("%d\n",vis[tid]);
            else{
                printf("Impossible\n");
            }
        }
    }
}

G - Shuffle'm Up dbfs

没有注意到每次只有一种转移,以为状态数会很多,就写了一个dbfs,发现第一次写问题还是蛮多的,首先就是控制两边的深度平衡,但同时要保证是非空的队列才能操作,每次操作完应该可以更新深度也可以不更新。反向搜索时要注意状态是反向转移的。

#include<bits/stdc++.h>
using namespace std;
#define ll long long


string ss,st;
map<string,int>m1;
map<string,int>m2;

queue<pair<string,int> >q1;
queue<pair<string,int> >q2;


int C;
int len;
string s,ns;
int ans;

void dbfs(){

    int t1=0,t2=0;
    m1[ss]=t1;
    m2[st]=t2;
    q1.push({ss,t1});
    q2.push({st,t2});
    while(!q1.empty()||!q2.empty()){
        if(t1<=t2&&!q1.empty()){
            s=q1.front().first;
            //cout<<"s1="<<s<<endl;
            q1.pop();

            ns.resize(len);
            for(int i=0;i<len;i++){
                if(i%2==0){
                    ns[i]=s[C+i/2];
                }
                else{
                    ns[i]=s[i/2];
                }
            }
            //cout<<"ns1="<<ns<<endl;
            if(m2.count(ns)){
                ans=m2[ns]+t1+1;
                return;
            }
            if(m1.count(ns)==0){
                q1.push({ns,t1+1});
                m1[ns]=t1+1;
                t1=q1.front().second;
            }
        }
        else if(!q2.empty()){
            s=q2.front().first;
            //cout<<"s2="<<s<<endl;

            q2.pop();

            ns.resize(len);
            //这里应该是倒退步骤
            for(int i=0;i<C;i++){
                ns[i]=s[2*i+1];
            }
            for(int i=C;i<len;i++){
                ns[i]=s[2*(i-C)];
            }


            if(m1.count(ns)){
                ans=m1[ns]+t2+1;
                return;
            }
            if(m2.count(ns)==0){
                q2.push({ns,t2+1});
                m2[ns]=t2+1;
                t2=q2.front().second;
            }
        }
        else{
            s=q1.front().first;
            //cout<<"s1="<<s<<endl;
            q1.pop();

            ns.resize(len);
            for(int i=0;i<len;i++){
                if(i%2==0){
                    ns[i]=s[C+i/2];
                }
                else{
                    ns[i]=s[i/2];
                }
            }
            //cout<<"ns1="<<ns<<endl;
            if(m2.count(ns)){
                ans=m2[ns]+t1+1;
                return;
            }
            if(m1.count(ns)==0){
                q1.push({ns,t1+1});
                m1[ns]=t1+1;
                t1=q1.front().second;
            }
        }
    }
}

int main(){
    int T;
    while(~scanf("%d",&T)){
        for(int t=1;t<=T;t++){
            m1.clear();
            m2.clear();

            while(!q1.empty()) q1.pop();
            while(!q2.empty()) q2.pop();

            scanf("%d",&C);
            len=2*C;
            string s1,s2;
            cin>>s1>>s2>>st;
            ss=s1+s2;

            if(ss==st){
                printf("%d %d\n",t,0);
                continue;
            }

            ans=-1;
            dbfs();
            printf("%d %d\n",t,ans);
        }
    }
}

H - Pots bfs

好几个点差点弄错了。比如gett[C]找到会会被下一次覆盖,比如impossible,比如一开始是空pot,比如用memset来给pair和string赋值?还有一个是交上去错了是DROP(1,2)忘记改过来?!所以说这种需要还原步骤的应该怎么写呢?最后还是用一个struct来写吧。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int A,B,C;
int a,b;
pair<int,string> g[105][105];
pair<int,int> f[105][105];
int gett[105];
int gettCa,gettCb;
pair<pair<int,int>,int> p;
queue<pair<pair<int,int>,int> > Q;

void bfs(){
    while(!Q.empty())
        Q.pop();
    Q.push({{0,0},0});
    g[0][0]={0,""};
    while(!Q.empty()){
        a=Q.front().first.first;
        b=Q.front().first.second;
        //cout<<a<<" "<<b<<" "<<g[a][b].second<<endl;

        int pt=Q.front().second;
        Q.pop();

        if(pt+1<g[A][b].first){
            g[A][b].first=pt+1;
            Q.push({{A,b},pt+1});
            g[A][b].second="FILL(1)";
            f[A][b]={a,b};
            gett[A]=1;
            gett[b]=1;
            if(gett[C]==1){
                gettCa=A;
                gettCb=b;
                while(!Q.empty()){
                    Q.pop();
                }
                return;

            }
        }

        if(pt+1<g[a][B].first){
            g[a][B].first=pt+1;
            g[a][B].second="FILL(2)";
            Q.push({{a,B},pt+1});
            f[a][B]={a,b};
            gett[a]=1;
            gett[B]=1;
            if(gett[C]==1){
                gettCa=a;
                gettCb=B;
                while(!Q.empty()){
                    Q.pop();
                }
                return;
            }
        }
        if(pt+1<g[0][b].first){
            g[0][b].first=pt+1;
            g[0][b].second="DROP(1)";
            Q.push({{0,b},pt+1});
            f[0][b]={a,b};
            gett[0]=1;
            gett[b]=1;
            if(gett[C]==1){
                gettCa=0;
                gettCb=b;
                while(!Q.empty()){
                    Q.pop();
                }
                return;
            }
        }
        if(pt+1<g[a][0].first){
            g[a][0].first=pt+1;
            g[a][0].second="DROP(2)";
            Q.push({{a,0},pt+1});
            f[a][0]={a,b};
            gett[a]=1;
            gett[0]=1;
            if(gett[C]==1){
                gettCa=a;
                gettCb=0;
                while(!Q.empty()){
                    Q.pop();
                }
                return;
            }
        }

        int da=a-min(a,B-b);
        int db=b+min(a,B-b);
        if(pt+1<g[da][db].first){
            g[da][db].first=pt+1;
            g[da][db].second="POUR(1,2)";
            Q.push({{da,db},pt+1});
            f[da][db]={a,b};
            gett[da]=1;
            gett[db]=1;
            if(gett[C]==1){
                gettCa=da;
                gettCb=db;
                while(!Q.empty()){
                    Q.pop();
                }
                return;
            }
        }

        da=a+min(A-a,b);
        db=b-min(A-a,b);
        if(pt+1<g[da][db].first){
            g[da][db].first=pt+1;
            g[da][db].second="POUR(2,1)";
            Q.push({{da,db},pt+1});
            f[da][db]={a,b};
            gett[da]=1;
            gett[db]=1;
            if(gett[C]==1){
                gettCa=da;
                gettCb=db;
                while(!Q.empty()){
                    Q.pop();
                }
                return;
            }
        }

        if(gett[C]==1){
            while(!Q.empty()){
                Q.pop();
            }
            break;
        }
    }
}

int main(){
    while(~scanf("%d%d%d",&A,&B,&C)){
        for(int i=0;i<105;i++){
            for(int j=0;j<105;j++){
                g[i][j].first=0x3f3f3f3f;
            }
        }
        memset(gett,0,sizeof(gett));
        bfs();
        if(gett[C]==1){
            string ans;
            int cnt=0;
            int cura=gettCa,curb=gettCb;
            while(cura!=0||curb!=0){
                //cout<<ans<<endl;
                ans=g[cura][curb].second+'\n'+ans;
                int copycura=cura;
                cura=f[cura][curb].first;
                curb=f[copycura][curb].second;
                cnt++;
            }
            printf("%d\n",cnt);
            cout<<ans;
        }
        else{
            puts("impossible");
        }
    }
}

I - Fire! bfs

读错题(原本没读错)以为只有一堆火,最后又把火是无穷判作不合法。

以后bfs还在专门写个enqueue函数来做比较方便,而且vis数组要规定墙是-1,待扩展是无穷。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int N,M;
char g[1005][1005];
int tf[1005][1005];
int tj[1005][1005];

struct cor{
    int i,j,t;
    char c;
    cor(int ii=0,int jj=0,int tt=0,char cc=' '){
        i=ii,j=jj,t=tt;
        c=cc;
    }
};
queue<cor> Q;
int ji,jj;
int fi[1005*1005],fj[1005*1005];
int cntf;

void bfs(){
    while(!Q.empty()){
        Q.pop();
    }

    for(int i=0;i<cntf;i++){
        tf[fi[i]][fj[i]]=0;
        Q.push(cor(fi[i],fj[i],0,'F'));
    }

    while(!Q.empty()){
        cor c=Q.front();
        Q.pop();

        if(c.i>0&&tf[c.i-1][c.j]==0x3f3f3f3f){
            tf[c.i-1][c.j]=c.t+1;
            Q.push(cor(c.i-1,c.j,c.t+1,'F'));
        }
        if(c.i+1<N&&tf[c.i+1][c.j]==0x3f3f3f3f){
            tf[c.i+1][c.j]=c.t+1;
            Q.push(cor(c.i+1,c.j,c.t+1,'F'));
        }
        if(c.j>0&&tf[c.i][c.j-1]==0x3f3f3f3f){
            tf[c.i][c.j-1]=c.t+1;
            Q.push(cor(c.i,c.j-1,c.t+1,'F'));
        }
        if(c.j+1<M&&tf[c.i][c.j+1]==0x3f3f3f3f){
            tf[c.i][c.j+1]=c.t+1;
            Q.push(cor(c.i,c.j+1,c.t+1,'F'));
        }
    }


    tj[ji][jj]=0;
    Q.push(cor(ji,jj,0,'J'));
    while(!Q.empty()){
        cor c=Q.front();
        Q.pop();

        if(c.i>0&&tj[c.i-1][c.j]==0x3f3f3f3f){
            tj[c.i-1][c.j]=c.t+1;
            Q.push(cor(c.i-1,c.j,c.t+1,'J'));
        }
        if(c.i+1<N&&tj[c.i+1][c.j]==0x3f3f3f3f){
            tj[c.i+1][c.j]=c.t+1;
            Q.push(cor(c.i+1,c.j,c.t+1,'J'));
        }
        if(c.j>0&&tj[c.i][c.j-1]==0x3f3f3f3f){
            tj[c.i][c.j-1]=c.t+1;
            Q.push(cor(c.i,c.j-1,c.t+1,'J'));
        }
        if(c.j+1<M&&tj[c.i][c.j+1]==0x3f3f3f3f){
            tj[c.i][c.j+1]=c.t+1;
            Q.push(cor(c.i,c.j+1,c.t+1,'J'));
        }
    }
    /*printf("F:\n");
    for(int i=0;i<N;i++){
        for(int j=0;j<M;j++){
           printf(" %d",tf[i][j]);
        }
        printf("\n");
    }
    printf("J:\n");
    for(int i=0;i<N;i++){
        for(int j=0;j<M;j++){
           printf(" %d",tj[i][j]);
        }
        printf("\n");
    }*/
}

int main(){
    int T;
    while(~scanf("%d",&T)){
        while(T--){
            scanf("%d%d",&N,&M);
            for(int i=0;i<N;i++){
                scanf("%s",g[i]);
            }
            cntf=0;
            for(int i=0;i<N;i++){
                for(int j=0;j<M;j++){
                    if(g[i][j]=='#'){
                        tf[i][j]=-1;
                        tj[i][j]=-1;
                    }
                    else{
                        tf[i][j]=0x3f3f3f3f;
                        tj[i][j]=0x3f3f3f3f;
                        if(g[i][j]=='F'){
                            fi[cntf]=i;fj[cntf]=j;
                            cntf++;
                        }
                        else if(g[i][j]=='J'){
                            ji=i,jj=j;
                        }
                    }

                }
            }
            bfs();
            int mint=0x3f3f3f3f;
            for(int i=0;i<N;i++){
                if(tf[i][0]>=0&&tj[i][0]>=0&&tj[i][0]!=0x3f3f3f3f){
                    if(tj[i][0]<tf[i][0]){
                        mint=min(mint,tj[i][0]);
                    }
                }
                if(tf[i][M-1]>=0&&tj[i][M-1]>=0&&tj[i][M-1]!=0x3f3f3f3f){
                    if(tj[i][M-1]<tf[i][M-1]){
                        mint=min(mint,tj[i][M-1]);
                    }
                }
            }
            for(int j=0;j<M;j++){
                if(tf[0][j]>=0&&tj[0][j]>=0&&tj[0][j]!=0x3f3f3f3f){
                    if(tj[0][j]<tf[0][j]){
                        mint=min(mint,tj[0][j]);
                    }
                }
                if(tf[N-1][j]>=0&&tj[N-1][j]>=0&&tj[N-1][j]!=0x3f3f3f3f){
                    if(tj[N-1][j]<tf[N-1][j]){
                        mint=min(mint,tj[N-1][j]);
                    }
                }
            }
            if(mint!=0x3f3f3f3f){
                printf("%d\n",mint+1);
            }
            else{
                printf("IMPOSSIBLE\n");
            }
        }
    }
}

J - 迷宫问题 bfs

打个标记表示来自哪个方向即可,用stack回溯。想着进阶搜索里也耍这个花招,呵呵,死得很惨。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int n;
int g[6][6];
int vis[6][6];
int di[6][6];

struct cor{
    int i,j;
    int t;
    char d;
    //from u,d,l,r

    cor(){}
    cor(int ii,int jj,int tt,char dd):i(ii),j(jj),t(tt),d(dd){}
};

queue<cor> Q;
void enqueue(int i,int j,int t,int d){
    if(i<0||i>=5)
        return;
    if(j<0||j>=5)
        return;
    if(vis[i][j]!=0)
        return;
    vis[i][j]=2;
    Q.push(cor(i,j,t,d));
}

void bfs(){
    Q.push(cor(0,0,0,'o'));
    while(!Q.empty()){
        cor c=Q.front();
        vis[c.i][c.j]=3;
        di[c.i][c.j]=c.d;
        Q.pop();
        enqueue(c.i-1,c.j,c.t+1,'d');
        enqueue(c.i+1,c.j,c.t+1,'u');
        enqueue(c.i,c.j-1,c.t+1,'r');
        enqueue(c.i,c.j+1,c.t+1,'l');
    }
}

void output(){
    stack<string>ans;
    ans.push("(4, 4)");
    int i=4,j=4;
    while(i||j){
        if(di[i][j]=='u')
            i--;
        else if(di[i][j]=='d')
            i++;
        else if(di[i][j]=='l')
            j--;
        else
            j++;
        string s="(";
        s+=char('0'+i);
        s+=", ";
        s+=char('0'+j);
        s+=')';
        ans.push(s);
    }

    while(!ans.empty()){
        cout<<ans.top()<<endl;
        ans.pop();
    }
}

int main(){
    while(~scanf("%d",&g[0][0])){
        for(int i=0;i<5;i++){
            for(int j=0;j<5;j++){
                if(i+j){
                    scanf("%d",&g[i][j]);
                }
                vis[i][j]=g[i][j];
            }
        }
        bfs();
        output();
    }
}



K - Oil Deposits dfs/bfs

想起来,去年我最喜欢这题了。记得清空vis和进入dfs前判断vis就好。dfs应该比较好写?

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int n,m;
char g[105][105];
int vis[105][105];

void dfs(int i,int j){
    if(i<0||i>=n)
        return;
    if(j<0||j>=m)
        return;
    if(vis[i][j]!=0)
        return;
    vis[i][j]=1;
    if(g[i][j]=='@'){
        for(int di=-1;di<=1;di++){
            for(int dj=-1;dj<=1;dj++){
                dfs(i+di,j+dj);
            }
        }
    }
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        if(n==0)
            break;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++){
            scanf("%s",&g[i]);
        }
        int ans=0;

        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(g[i][j]=='@'&&vis[i][j]==0){
                    ans++;
                    dfs(i,j);
                }
            }
        }

        printf("%d\n",ans);
    }
}



L - 非常可乐 bfs

很有趣的一个题目,搞清楚倒可乐的转移步骤就很好写。这个还好,可以用数组表示,假如再大的话是不是要用set来计重了?总之所有的最短次数都是用bfs没跑了。(注意memset确实是以1字节为单位赋值的,可以memset(g,0x3f,sizeof(g))

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int S,N,M;

int g[105][105][105];

struct sta{
    int s,n,m,t;
    sta(){};
    sta(int ss,int nn,int mm,int tt){
        s=ss,n=nn,m=mm,t=tt;
    }
}s1;

queue<sta> Q;

void enqueue(int s,int n,int m,int t){
    //cout<<s<<" "<<n<<" "<<m<<endl;
    if(g[s][n][m]==0x3f3f3f3f){
        g[s][n][m]=t;
        Q.push(sta(s,n,m,t));
    }
    else
        ;
}

void bfs(){
    while(!Q.empty())
        Q.pop();
    Q.push(sta(S,0,0,0));
    while(!Q.empty()){
        s1=Q.front();
        Q.pop();
        //cout<<s1.s<<" "<<s1.n<<" "<<s1.m<<endl;
        int t=s1.t;
        enqueue(s1.s-min(s1.s,N-s1.n),s1.n+min(s1.s,N-s1.n),s1.m,t+1);
        enqueue(s1.s-min(s1.s,M-s1.m),s1.n,s1.m+min(s1.s,M-s1.m),t+1);
        enqueue(s1.s,s1.n-min(s1.n,M-s1.m),s1.m+min(s1.n,M-s1.m),t+1);
        enqueue(s1.s+min(S-s1.s,s1.n),s1.n-min(s1.n,S-s1.s),s1.m,t+1);
        enqueue(s1.s+min(S-s1.s,s1.m),s1.n,s1.m-min(s1.m,S-s1.s),t+1);
        enqueue(s1.s,s1.n+min(N-s1.n,s1.m),s1.m-min(N-s1.n,s1.m),t+1);
    }
}


int main(){
    while(~scanf("%d%d%d",&S,&N,&M)){
        if(S==0&&N==0&&M==0)
            break;
        if(S%2){
            puts("NO");
            continue;
        }

        memset(g,0x3f,sizeof(g));
        int ans=0x3f3f3f3f;
        bfs();
        ans=min(g[S/2][S/2][0],g[0][S/2][S/2]);
        ans=min(g[S/2][0][S/2],ans);
        if(ans==0x3f3f3f3f)
            puts("NO");
        else
            printf("%d\n",ans);
    }
}



M - Find a way bfs

 我居然WA2了,没有解决KFC不能到的情况,然后把vis从0变成-1之后还是有问题,说明以后应该默认把距离改成无穷。也就是-1表示不能扩展,inf表示待扩展,正常的非负数表示距离。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int n,m;

char g[205][205];
int vis1[205][205];
int vis2[205][205];

struct cor{
    int i,j,t,c;
    cor(int ii=0,int jj=0,int tt=0,int cc=0){
        i=ii,j=jj,t=tt,c=cc;
    }
};
queue<cor> Q;

int mind;

int yi,yj;
int mi,mj;

void bfs(){
    vis1[yi][yj]=-1;
    Q.push(cor(yi,yj,0,1));
    vis2[mi][mj]=-1;
    Q.push(cor(mi,mj,0,2));
    while(!Q.empty()){
        cor c=Q.front();
        //cout<<c.i<<" "<<c.j<<" "<<c.c<<endl;
        Q.pop();
        if(c.c==1){
            if(c.i>0&&vis1[c.i-1][c.j]==0){
                vis1[c.i-1][c.j]=c.t+1;
                Q.push(cor(c.i-1,c.j,c.t+1,1));
            }
            if(c.i+1<n&&vis1[c.i+1][c.j]==0){
                vis1[c.i+1][c.j]=c.t+1;
                Q.push(cor(c.i+1,c.j,c.t+1,1));
            }
            if(c.j>0&&vis1[c.i][c.j-1]==0){
                vis1[c.i][c.j-1]=c.t+1;
                Q.push(cor(c.i,c.j-1,c.t+1,1));
            }
            if(c.j+1<m&&vis1[c.i][c.j+1]==0){
                vis1[c.i][c.j+1]=c.t+1;
                Q.push(cor(c.i,c.j+1,c.t+1,1));
            }

        }
        else if(c.c==2){
            if(c.i>0&&vis2[c.i-1][c.j]==0){
                vis2[c.i-1][c.j]=c.t+1;
                Q.push(cor(c.i-1,c.j,c.t+1,2));
            }
            if(c.i+1<n&&vis2[c.i+1][c.j]==0){
                vis2[c.i+1][c.j]=c.t+1;
                Q.push(cor(c.i+1,c.j,c.t+1,2));
            }
            if(c.j>0&&vis2[c.i][c.j-1]==0){
                vis2[c.i][c.j-1]=c.t+1;
                Q.push(cor(c.i,c.j-1,c.t+1,2));
            }
            if(c.j+1<m&&vis2[c.i][c.j+1]==0){
                vis2[c.i][c.j+1]=c.t+1;
                Q.push(cor(c.i,c.j+1,c.t+1,2));
            }
        }
    }

    /*for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(vis1[i][j]==0)
                vis1[i][j]=-1;
            if(vis1[i][j]==0)
                vis1[i][j]=-2;
        }
    }*/

    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            //printf("% 3d",vis1[i][j]);
            if(g[i][j]=='@'&&vis1[i][j]>0&&vis2[i][j]>0&&mind>vis1[i][j]+vis2[i][j]){
                mind=(vis1[i][j]+vis2[i][j]);
            }
        }
       // printf("\n");
    }

}

int main(){
    while(~scanf("%d%d",&n,&m)){
        for(int i=0;i<n;i++){
            scanf("%s",g[i]);
        }

        memset(vis1,0,sizeof(vis1));
        memset(vis2,0,sizeof(vis2));
        mind=0x3f3f3f3f;

        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(g[i][j]=='Y'){
                    yi=i,yj=j;
                }
                else if(g[i][j]=='M'){
                    mi=i,mj=j;
                }
                else if(g[i][j]=='#'){
                    vis1[i][j]=-1;
                    vis2[i][j]=-1;
                }
            }
        }

        bfs();
        printf("%d\n",11*mind);
    }
}

总结

1.dfs进入时标记状态,退出时清除标记

2.bfs等需要保持步数、转移方向等的时候最好定义结构体

3.我好像喜欢把bfs的入队写成enqueue()函数,可能跟我喜欢写dfs有关。

4.初始化、清空是个好习惯。

 

### 关于 kuangbin ACM 算法竞赛培训计划 #### 数论基础专题介绍 “kuangbin专题十四涵盖了数论基础知识的学习,旨在帮助参赛者掌握算法竞赛中常用的数论概念和技术。该系列不仅提供了丰富的理论讲解,还推荐了本详细的书籍《算法竞赛中的初等数论》,这本书包含了ACM、OI以及MO所需的基础到高级的数论知识点[^1]。 #### 并查集应用实例 在另个具体的例子中,“kuangbin”的第五个专题聚焦于并查集的应用。通过解决实际问题如病毒感染案例分析来加深理解。在这个场景下,给定组学生及其所属的不同社团关系图,目标是从这些信息出发找出所有可能被传染的学生数目。此过程涉及到了如何高效管理和查询集合成员之间的连通性问题[^2]。 #### 搜索技巧提升指南 对于简单搜索题目而言,在为期约两周的时间里完成了这部分内容的学习;尽管看似容易,但对于更复杂的状况比如状态压缩或是路径重建等问题,则建议进步加强训练以提高解题能力[^3]。 ```python def find_parent(parent, i): if parent[i] == i: return i return find_parent(parent, parent[i]) def union(parent, rank, x, y): rootX = find_parent(parent, x) rootY = find_parent(parent, y) if rootX != rootY: if rank[rootX] < rank[rootY]: parent[rootX] = rootY elif rank[rootX] > rank[rootY]: parent[rootY] = rootX else : parent[rootY] = rootX rank[rootX] += 1 # Example usage of Union-Find algorithm to solve the virus spread problem. ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值