zoukankan      html  css  js  c++  java
  • [BFS] POJ 2251 Dungeon Master | POJ 3278 Catch That Cow | POJ 3126 Prime Path | POJ 3414 Pots

    BFS(1)

    BFS(2):queue中状态结构体类型不止不止当前val

    BFS(3):多源BFS

    BFS(1)

    2251

    #include"stdio.h"
    #include"limits.h"
    #include"string.h"
    #include<queue>
    using namespace std;
    const int MAX_L = 32;
    const int MAX_R = 32;
    const int MAX_C = 32;
    struct Pos{
        int i;int j;int k;
        int lv;
        Pos(int i_,int j_,int k_,int lv_):i(i_),j(j_),k(k_),lv(lv_){}
    };
    char dungeon[MAX_L][MAX_R][MAX_C];
    char vist[MAX_L][MAX_R][MAX_C];
    int L,R,C;
    int S[3];
    int E[3];
    int min_n=INT_MAX;
    int n=0;
    int to[3][6]={{-1,+1,0,0,0,0},
                {0,0,-1,+1,0,0},
                {0,0,0,0,-1,+1}};
    bool isValid(int i,int j,int k){
        if(i<0||i>=L || j<0||j>=R || k<0||k>=C) return false;
        if(dungeon[i][j][k]=='#') return false;
        if(vist[i][j][k]) return false;
        return true;
    }
    int bfs(int si,int sj,int sk){
        queue<Pos> Q;
        Q.push(Pos(si,sj,sk,0));
        vist[si][sj][sk]=true;
        while(!Q.empty()){
            Pos p=Q.front();
            int i=p.i; int j=p.j; int k=p.k; int lv=p.lv;
            Q.pop();
            if(dungeon[i][j][k]=='E') {
                return lv;
            }
            for(int t=0;t<6;t++){
                // 判断条件放在push前,相比于取出可能无效数据后判断,减少push/pop
                if(isValid(i+to[0][t],j+to[1][t],k+to[2][t])){
                    // 访问标记与push两个操作同时进行。相比于pop后再标记可以实现更有效的剪枝
                    vist[i+to[0][t]][j+to[1][t]][k+to[2][t]]=true;
                    Q.push(Pos(i+to[0][t],j+to[1][t],k+to[2][t],lv+1));
                }
            }
        }
        return -1;
    }
    int main(){
    
        while(1){
            scanf("%d %d %d",&L,&R,&C);
            if(!L &&!R && !C) break;
            memset(dungeon,'#',MAX_L*MAX_R*MAX_C);
            memset(vist,0,MAX_L*MAX_R*MAX_C);
            min_n=INT_MAX;
            n=0;
            for(int i=0;i<L;i++){
                for(int j=0;j<R;j++){
                    scanf("%s",dungeon[i][j]);
                    for(int k=0;k<C;k++){
                        if(dungeon[i][j][k]=='S') {S[0]=i;S[1]=j;S[2]=k;}
                        else if(dungeon[i][j][k]=='E') {E[0]=i;E[1]=j;E[2]=k;}
                    }
                }
                // 自动忽略whitespace character
            }
            int x=bfs(S[0],S[1],S[2]);
            if(x!=-1) printf("Escaped in %d minute(s).
    ",x);
            else printf("Trapped!
    ");
        }
    }
    

    3278

    #include"stdio.h"
    #include"string.h"
    #include<queue>
    using namespace std;
    
    const int MAX_N=100010;
    int N,K;
    int vist[MAX_N];
    bool check(int x){
        if(x<0 || x>100000) return false;
        if(vist[x]) return false;
        return true;
    }
    int bfs(){
        queue<int> Q;
        Q.push(N);
        vist[N]=1;
        while(!Q.empty()){
            int x = Q.front();
            Q.pop();
            if(x==K) return vist[x]-1;
            int choice[3]={x+1,x-1,2*x};
            for(int i=0;i<3;i++){
                if(check(choice[i])){
                    vist[choice[i]] = vist[x]+1;
                    Q.push(choice[i]);
                }
            }
        }
    
    
    }
    int main(){
        memset(vist,0,MAX_N);
        scanf("%d %d",&N,&K);
        int x = bfs();
        printf("%d
    ",x);
    }
    

    BFS(2)

    3126

    #include"stdio.h"
    #include"string.h"
    #include<queue>
    #include<set>
    using namespace std;
    
    int isPrime[10000];// queue中元素类型用结构体维护除了val,step,还有vis
    struct St{
        int x;  // 4-digit 0~9
        int pre_vis;// 0~3
        int step;
        St(){}
        St(int x_,int p_,int s_):x(x_),pre_vis(p_),step(s_){}
    };
    int pow[]={1,10,100,1000};
    int main(){
        memset(isPrime,1,sizeof(isPrime));
        isPrime[1]=false;
        for(int i=2;i<10000;i++){
            if(!isPrime[i]) continue;
            for(int k=i+i;k<10000;k+=i){
                isPrime[k] = 0;
            }
        }
        int N;
        scanf("%d",&N);
        for(int n=0;n<N;n++){
            int src;
            int dst;
            scanf("%d %d",&src,&dst);
            
            set<int> S; // 若不加这个set防止path成环,会TLE
            queue<St> Q;
            Q.push(St(src,-1,0));
            St st;
            while(!Q.empty()){
                st = Q.front();
                Q.pop();
                if(st.x==dst) break;
                for(int i=0;i<4;i++){
                    if(i==st.pre_vis) continue;
                    for(int j=0;j<10;j++){
                        if(i==3 && j==0) continue;  // without leading zero
                        // change digit i
                        int dig = (st.x%(int)pow[i+1]) / pow[i];
                        if(j==dig) continue;
                        int nextx = st.x - (dig-j)*pow[i];
                        if(isPrime[nextx] && S.count(nextx)==0) {
                            Q.push(St(nextx, i, st.step+1));
                            S.insert(nextx);
                        }
                    }
                }
            }
            printf("%d
    ",st.step);
        }
    }
    

    3414

    #include<iostream>
    #include"math.h"
    #include<queue>
    #include<set>
    #include<string>
    // codeblocks上可以不#include<vector>,poj上必须include
    #include<vector>
    using namespace std;
    typedef pair<int,int> Pair;
    // poj [Compile Error] non-aggregates cannot be initialized with initializer list
    // vector<string> otpt={"FILL","DROP","POUR"};
    char otpt[3][5]={"FILL","DROP","POUR"};
    struct Op{
        int o;// 0-FILL,1-DROP,2-POUR
        int p;// 1-pot1,2-pot2
        Op(int o_,int p_):o(o_),p(p_){}
    };
    struct St{
        int pot1,pot2;
        vector<Op> path;
        St(){}
        St(int p1,int p2):pot1(p1),pot2(p2){}
        St(int p1,int p2,vector<Op> p_):pot1(p1),pot2(p2),path(p_){}
    };
    
    int main(){
        int A,B,C;
        cin>>A>>B>>C;
        /* 本来想用St做M集合中的元素类型 */
        /* <map>内部有序,结构体须重载operator<
        /* <unordered_map>结构体须实现Hash
        /* 改用pair<int,int>做M集合中的元素类型 */
        set<Pair> M;
        /* 操作路径是状态的一部分,实现时放到St里*/
        // vector<Op> path;
        queue<St> Q;
        M.insert(Pair(0,0));
        Q.push(St(0,0));
        St st;
        while(!Q.empty()){
            st = Q.front();
            Q.pop();
            if(st.pot1==C || st.pot2==C) break;
            if(st.pot1<A) {// FILL(1)
                vector<Op> to = st.path; to.push_back(Op(0,1));
                St tmp(A, st.pot2, to);
                Pair p(A, st.pot2);
                /* 不在考虑已经经过的状态 */
                // continue rather than break
                if(!M.count(p)) {
                    M.insert(p);
                    Q.push(tmp);
                }
            }
            if(st.pot1>0) {// DROP(1)
                vector<Op> to = st.path; to.push_back(Op(1,1));
                St tmp(0, st.pot2, to);
                Pair p(0, st.pot2);
                if(!M.count(p)) {
                    M.insert(p);
                    Q.push(tmp);
                }
            }
            if(st.pot1>0 && st.pot2<B){// POUR(1,2)
                vector<Op> to = st.path; to.push_back(Op(2,1));
                int poured = min(B-st.pot2,st.pot1);
                St tmp(st.pot1-poured, st.pot2+poured, to);
                Pair p(st.pot1-poured, st.pot2+poured);
                if(!M.count(p)) {
                    M.insert(p);
                    Q.push(tmp);
                }
            }
            if(st.pot2<B) {// FILL(2)
                vector<Op> to = st.path; to.push_back(Op(0,2));
                St tmp(st.pot1,B, to);
                Pair p(st.pot1,B);
                if(!M.count(p)) {
                    M.insert(p);
                    Q.push(tmp);
                }
            }
            if(st.pot2>0) {// DROP(2)
                vector<Op> to = st.path; to.push_back(Op(1,2));
                St tmp(st.pot1,0, to);
                Pair p(st.pot1,0);
                if(!M.count(p)) {
                    M.insert(p);
                    Q.push(tmp);
                }
            }
            if(st.pot1<A && st.pot2>0){// POUR(2,1)
                vector<Op> to = st.path; to.push_back(Op(2,2));
                int poured = min(A-st.pot1,st.pot2);
                St tmp(st.pot1+poured, st.pot2-poured,to);
                Pair p(st.pot1+poured, st.pot2-poured);
                if(!M.count(p)) {
                    M.insert(p);
                    Q.push(tmp);
                }
            }
        }
        if(st.pot1==C || st.pot2==C) {
            int n = st.path.size();
            printf("%d
    ",n);
            vector<Op> out = st.path;
            for(int i=0;i<n;i++){
                printf("%s",otpt[out[i].o]);
                printf("(%d",out[i].p);
                if(out[i].o==2){
                    printf(",%d",3-out[i].p);
                }
                printf(")
    ");
            }
        }else {
            printf("impossible
    ");
        }
    }
    

    BFS(3)

    FZU 2150 Fire Game  双起点BFS

    • 状态包含 {n, m} or {n1, m1, n2, m2}?前者。若用后者,DFS会TLE,BFS会MLE
    • 用DFS or BFS?双起点(有关联的两棵树):无法用dfs,用bfs
    #include<iostream>
    #include<queue>
    #include<utility>
    #include"string.h"
    #include"math.h"
    using namespace std;
    struct St{
        int n,m;
        int s;
        St(){}
        St(int n_,int m_,int s_):n(n_),m(m_),s(s_){}
    };
    struct Pos{
        int n,m;
        Pos(int n_,int m_):n(n_),m(m_){}
    };
    const int MAX_N=10;
    const int MAX_M=10;
    char board[MAX_N][MAX_M];
    int step[MAX_N][MAX_M];
    int N,M;
    const int to[4][2]={{-1,0},{1,0},{0,-1},{0,1}};// 为什么要维护所有#的位置?// 若用四重for循环,重复多;若内层两层for循环初始化为外层两层的值,ii=i, jj=j,实现的逻辑是(错误的:)接着遍历子矩阵,而非剩下所有。
    vector<Pos> grass;
    
    void display(){
        for(int i=0;i<N;i++){
            for(int j=0;j<M;j++)
                printf("%d ", step[i][j]);
            printf("
    ");
        }
    }
    bool check(){
        for(int i=0;i<N;i++){
            for(int j=0;j<M;j++){
                if(board[i][j]=='#' && step[i][j]<0)
                    return false;
            }
        }
        return true;
    }
    int bfs_step(int n1,int m1,int n2,int m2){
        queue<St> Q;
        Q.push(St(n1,m1,0));
        Q.push(St(n2,m2,0));
        step[n1][m1] = 0;
        step[n2][m2] = 0;
        St p;
        while(!Q.empty()){
            p = Q.front();
            Q.pop();
            for(int i=0;i<4;i++){
                int x=p.n+to[i][0];
                int y=p.m+to[i][1];
                if(x<0 || x>=N ||y<0 || y>=M) continue;
                if(board[x][y]!='#') continue;
                if(step[x][y]>=0) continue;
                step[x][y] = p.s+1;
                Q.push(St(x,y,p.s+1));
            }
        }
        return p.s;
    }/* 曾经的思路 */
    /* 先dfs得到连通分量的个数,然后分类讨论:/*   >2,返回-1;/*   =2,两个区域分别单起点搜索;/*   =1,单区域双起点搜索。/* 改进的思路 *//* 是否需要对连通分量个数分类讨论?简化:统一双起点BFS,搜索结束后check/* 因此不需要实现搜索一遍求连通分量个数。事实上,这么做TLE /* -------- */
    int solve(){
        int mins=0x3fffffff;
        for(unsigned i=0;i<grass.size();i++){
            for(unsigned j=i;j<grass.size();j++){
                
                memset(step,-1,sizeof(step));
                int maxs = bfs_step(grass[i].n,grass[i].m,grass[j].n,grass[j].m);
                // display();
                if(check()){
                    if(maxs < mins) mins = maxs;
                }
                
            }
        }
        
        if(mins==0x3fffffff) return -1;
        else return mins;
    }
    int main(){
        int T; scanf("%d",&T);
        for(int t=1;t<=T;t++){
            grass.clear();
            scanf("%d %d",&N,&M);
            for(int n=0;n<N;n++){
                scanf("%s",board[n]);
                for(int m=0;m<M;m++){
                    if(board[n][m]=='#') grass.push_back(Pos(n,m));
                }
            }        
            int time=solve();
            printf("Case %d: ", t);
            if(time==-1) printf("-1
    ");
            else printf("%d
    ",time);
        }
    }
    

    UVA 11624 Fire

    • 多个火和单个人公用一个队列还是分两个队列?
      • 都可以,关键是每次火和人都只能加一层深度。
      • 因此while不应以队列empty为判断条件,而应以该层火或人的数量作为while循环次数。
    • 火和人的vis数组应当共享(作全局变量)还是私有(增加path作为状态struct的数据成员)?
      • 火的vis数组显然做全局变量:已经燃烧到的地方终止进一步搜索
      • 人的vis数组:一条搜索路径visit过的地方,另一条搜索路径还需要再搜么?错过,仔细想想(不需要,否则TLE
    • 人无路可走的条件是什么?
      • 当前深度层所有搜索路径的所有方向都无路可走
      • 错过:当前深度层有一条搜索路径的所有方向无路可走
    #include"stdio.h"
    #include"string.h"
    #include<vector>
    #include<queue>
    #include<set>
    #include<utility>
    using namespace std;
    typedef pair<int,int> Coord;
    struct PosF{
        int r,c;    
        PosF(){}
        PosF(int r_,int c_):r(r_),c(c_){}
    };
    struct PosJ{
        int r,c;
        int s;//step
        PosJ(){}
        PosJ(int r_,int c_,int s_):r(r_),c(c_),s(s_){}
    };
    
    const int MAXRC=1003;
    int R,C;
    char maze[MAXRC][MAXRC];
    int visF[MAXRC][MAXRC];// 0-not visited, 1-visited
    int visJ[MAXRC][MAXRC];
    std::vector<Coord> Fs;//Fires
    Coord Joe;
    const int to[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    
    queue<PosF> QF;
    queue<PosJ> QJ;
    void bfsF(){
        int nF=QF.size();
        while((nF--)){
            PosF pF = QF.front();
            QF.pop();
            for(int i=0;i<4;i++){
                int x = pF.r + to[i][0];
                int y = pF.c + to[i][1];
                if(x<0 ||x>=R ||y<0 ||y>=C) continue;
                if(visF[x][y]) continue;
                if(maze[x][y]=='#') continue;
                QF.push(PosF(x,y));
                visF[x][y]=1;
            }
        }
    }
    int bfsJ(){
        int nJ=QJ.size();
        bool alive=false;
        while((nJ--)){
            PosJ pJ = QJ.front();
            QJ.pop();
            if(pJ.r==0 || pJ.r==R-1 || pJ.c==0 || pJ.c==C-1) return pJ.s;
            for(int i=0;i<4;i++){
                int x = pJ.r + to[i][0];
                int y = pJ.c + to[i][1];
                if(x<0 ||x>=R ||y<0 ||y>=C) continue;
                if(maze[x][y]=='#') continue;
                if(visF[x][y]) continue;
                if(visJ[x][y]) continue;
                if(x==0 || x==R-1 || y==0 || y==C-1) return pJ.s+1;
                alive=true;
                visJ[x][y] = 1;
                QJ.push(PosJ(x,y,pJ.s+1));
            }        
        }
        if(!alive) return -1;
        else return 0;
    }
    int solve(){
        for(int i=0;i<Fs.size();i++){
            int r = Fs[i].first;
            int c = Fs[i].second;
            QF.push(PosF(r,c));
            visF[r][c] = 1;
        }
    
        // set<Coord> S; S.insert(Coord(Joe.first,Joe.second));
        QJ.push(PosJ(Joe.first,Joe.second,1));
        visJ[Joe.first][Joe.second] = 1;
    
        bfsF();
        int ret;
        while((ret = bfsJ())==0) bfsF();
        return ret;
    }
    int main(){
        int T;
        scanf("%d",&T);
        for(int t=0;t<T;t++){
            // 
            memset(visF,0,sizeof(visF));
            memset(visJ,0,sizeof(visJ));
            Fs.clear();
            QJ = queue<PosJ>();
            QF = queue<PosF>();
            scanf("%d %d",&R,&C);
            for(int r=0;r<R;r++){
                scanf("%s",maze[r]);
                for(int c=0;c<C;c++){
                    if(maze[r][c]=='F') Fs.push_back(Coord(r,c));
                    if(maze[r][c]=='J') Joe = Coord(r,c);
                }
            }
            int ret = solve();
            if(ret==-1) printf("IMPOSSIBLE
    ");
            else printf("%d
    ", ret);
        }
        return 0;
    }
    
  • 相关阅读:
    Web中的通配符
    EJB版本
    package-info.java
    dynamic web module version
    深入解析和反思携程宕机事件
    Ubuntu 环境下使用cronolog 切割Tomcat日志
    ubuntu环境下cassandra安装配置
    zabbix自定义触发器语法
    zabbix系统邮件告警Python脚本
    Ubuntu14.04下zabbix2.4.5 源码编译安装
  • 原文地址:https://www.cnblogs.com/chengyh23/p/14536128.html
Copyright © 2011-2022 走看看