• 搜索入门_简单搜索bfs dfs大杂烩


    dfs题大杂烩

     

    棋盘问题  POJ - 1321

    和经典的八皇后问题一样.  给你一个棋盘,只有#区域可以放棋子,同时同一行和同一列只能有一个棋子. 问你放k个棋子有多少种方案.

    很明显,这是搜索题.

    因为每一行和每一列只能有一个棋子,所以我们可以从第k行一直到第n行枚举所有放棋子的情况,即我们从当前状态(当前行)dfs到第n行.然后符合添加的,我们就ans++.

    dfs过程见代码.

    #include <cstdio>
    #include <cstring>
    
    int n,k,c,way;
    
    // 检查当前棋盘区域是否可以放置棋子 
    bool isok(char vis[][16],int x,int y)
    {
        int i;
        for(i=0; i<n; ++i)
            if('V'==vis[x][i])
                return false;
        for(i=0; i<n; ++i)
            if('V'==vis[i][y])
                return false;
        return true;
    }
    
    void dfs(char vis[16][16],int cnt,int line)
    {
        int i,j;
        char mvis[16][16];
        
        if(k==cnt){
            c++;   // 走到了末尾 方案加一 
            return ;
        }else if(line==n){
            return ;
        }else if(n-line+cnt<k){ //"剪枝"
            return ;
        }else{        
            memcpy(mvis,vis,sizeof(mvis)); //注意sizeof的"陷阱",sizeof(指针)==4,所以不能传sizeof(vis) sizeof(数组名)==数组大小 
            for(i=line; i<n; ++i){    //注意i=line 而不是0 
                for(j=0; j<n; ++j){
                    if('#'==mvis[i][j] && isok(mvis,i,j)){  // 当前坐标是棋盘区域, 同时同一行同一列没有放置棋子 
                        mvis[i][j] = 'V';   // 放棋子 
                        dfs(mvis,cnt+1,i+1);
                        mvis[i][j] = '#';  // 取消放棋子的状态, 继续枚举其他情况            
                    }
                }
            }
            return ;
        }
    
    }
    
    int main()
    {
        int i,j;
        char map[16][16];    
    
    //    freopen("D:\input.txt","r",stdin);
        while(scanf("%d%d",&n,&k) && (n!=-1 || k!=-1)){
            for(i=0; i<n; ++i){
                scanf("%s",map[i]);
            }
            c=0;
            dfs(map,0,0);
            printf("%d
    ",c);
        }    
        return 0;
    }
    View Code

    Fliptile POJ - 3279

    给你一个0和1组成的矩阵.你可以将某一格子阵翻转.但是你翻转一个格子,他上下左右的格子也会背翻转.

    问你最后是否可以全部翻转成0

    如果可以输出一个矩阵: 对应01矩阵翻转的次数.要求该答案矩阵的翻转次数最少,同时如果有多个解,输出字典序最小的一个.

    如果不可以, 则输出IMPOSSIBLE

    首先,我们分析一下, 我们发现,对于一个格子来说,翻转偶数次是没有意义的.翻转奇数次,才会改变状态.

    因为对于一个格子,翻转偶数次是没有贡献的,翻转多个奇数次都等价于翻转一次,所以如果格子需要翻转,那么我们翻转一次就够了.

    同时,

    我们假定从第一行开始考虑, 如果要全部翻转成0, 那么我们当前行的状态将有由下一行同一列的格子翻转来决定.

    所以我们不难知道,如果上一行的这个格子是1的话,那么我们当前格子就需要翻转一下. 一直到最后一行翻转完毕,我们最后再判断一下最后一行是否全都是0,就可以确定答案是否存在.

    但是,我们这样并不能保证答案最优.. 我们不难发现这种做法依赖于第一行的初始状态. 因为最多只有十列,所以我们不妨把第一行的所有状态都枚举一下,然后都进行答案的查找.

    (ps,枚举状态可以用dfs或者二进制. 而我用的dfs搜索过去.)

    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    int _m[24][24];
    int _ct[24][24];
    int _ans[24][24];
    int tmp[24][24];
    int n, m;
    
    bool ishave;
    int qstep;
    int qsz = 1;
    
    inline int fff(int val, int mack) {
        return val ^ (1<<mack);
    } 
    
    void dfs(int now, int step) {
        int i, j;
        if (now > m) {
            
            // 注意,这里需要对矩阵进行操作,但是操作完成后,我们需要把还原原先的矩阵.
            // 所以我用了一个临时矩阵来保存. 
            memcpy(_ct, _m, sizeof(_ct));
            for (i=2; i<=n; ++i) {
                for (j=1; j<=m; ++j) {
                    if (_m[i-1][j]) {
                        _m[i][j]   = !_m[i][j];
                        _m[i-1][j] = !_m[i-1][j];
                        _m[i+1][j] = !_m[i+1][j];
                        _m[i][j-1] = !_m[i][j-1];
                        _m[i][j+1] = !_m[i][j+1];
                        tmp[i][j] = 1;
                        step++;
                    } else tmp[i][j] = 0;
                }
            }
    
            for (i=1; i<=m; ++i) if (_m[n][i]) { // 当前状态不能全部翻转为0 
                memcpy(_m, _ct, sizeof(_m));    
                return ;
            }
            if (step >  qstep) { // 步数判断 
                memcpy(_m, _ct, sizeof(_m));
                return ;
            }
            qstep = step;
            for (i=1; i<=n; ++i) { // 字典序判断, 注意,这个题的字典序是从右到左的. 
                for (j=m; j>=1; --j) {
                    if (tmp[i][j] != _ans[i][j]) goto A;
                }
            } 
            A: 
            if (i<=n && tmp[i][j] < _ans[i][j]) {
                ishave = true;
                for (i=1; i<=n; ++i) {
                    for (j=1; j<=m; ++j) 
                        _ans[i][j] = tmp[i][j];
                }
            }
            memcpy(_m, _ct, sizeof(_m));
            return ;
        }
        // 翻转第一行, 记得翻转的同时,周围的格子也会改变. 
        dfs(now+1, step);
        tmp[1][now] = 1;
        _m[1][now] = !_m[1][now];
        _m[1][now+1] = !_m[1][now+1];
        _m[1][now-1] = !_m[1][now-1];
        _m[2][now] = !_m[2][now];
        dfs(now+1, step+1);
        tmp[1][now] = 0;
        _m[1][now] = !_m[1][now];
        _m[1][now+1] = !_m[1][now+1];
        _m[1][now-1] = !_m[1][now-1];
        _m[2][now] = !_m[2][now];
    }
    /*
    4 4
    1 0 0 1
    0 1 1 0
    0 0 0 0
    0 0 0 0
    */
    int main()
    {
        int i, j;
        while (~scanf("%d%d", &n, &m)) {
            memset(_ans, 0x3f, sizeof(_ans));
            memset(tmp, 0, sizeof(tmp));
            int tmp = 0;
            int data;
            for (i=1; i<=n; ++i) 
                for (j=1; j<=m; ++j) 
                    scanf("%d", &_m[i][j]);
            ishave = false;
            qstep = 0x3f3f3f3f;
            dfs(1, 0);
            if (ishave) {
                for (i=1; i<=n; ++i) {
                    printf("%d",  _ans[i][1]);
                    for (j=2; j<=m; ++j) 
                        printf(" %d",  _ans[i][j]);
                    printf("
    ");
                }
            } else printf("IMPOSSIBLE
    ");
        }
        
        return 0;
    } 
    View Code

    Find The Multiple  POJ - 1426 

    给你一个数字,要你求出他的倍数,这个倍数由0和1组成.

    这个题利用了求模的一个性质  a%mod <==> (b*10+c)%mod 其中 a = b * 10 + c 

    所以,我们直接暴力搜过去就OK

    #include <cstdio>
    
    using namespace std;
    
    char ans[105];
    
    bool isover; 
    bool dfs(int val, int n, int deep) {
        if (!val) {    ans[deep] = ''; return isover = true; }
        if (isover) return true;
        if (deep==100) { return false; } 
        ans[deep] = '0';
        if (dfs(val*10%n, n, deep+1)) return true;
        ans[deep] = '1';
        if (dfs((val*10+1)%n, n, deep+1)) return true;
        return false;
    }
    
    int main()
    {
        int n;
        while (scanf("%d", &n) && n) {
            isover = false;
            ans[0] = '1';
            dfs(1%n, n, 1);
            printf("%s
    ", ans);
        }
        return 0;
    }
    View Code

    Oil Deposits  HDU - 1241

    简单的求连通块的个数. 八个方向的连通块. 直接dfs

    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    int n, m;
    
    char _m[104][104];
    bool vis[104][104];
    
    bool dfs(int x, int y) {
        if (x<0 || y<0 || x==n || y==m || vis[x][y] || _m[x][y]=='*') return false;
        vis[x][y] = true;
        dfs(x-1, y); dfs(x+1, y); dfs(x, y-1); dfs(x, y+1);
        dfs(x-1, y-1); dfs(x-1, y+1); dfs(x+1, y-1); dfs(x+1, y+1);
        return true;
    }
    
    int main()
    {
        int i, j, res;
        while (scanf("%d%d", &n, &m) && (n || m)) {
            memset(vis, 0, sizeof(vis));
            for (i=0; i<n; ++i) scanf("%s", _m[i]);
            res = 0;
            for (i=0; i<n; ++i) 
                for (j=0; j<m; ++j) 
                    res += dfs(i, j);
            printf("%d
    ", res);
        }
        
        return 0;
    }
    View Code

    Beautiful Now  HDU - 6351

    给你两个数字n和k, 问你数字n的数位经过至多k次交换后的最大值和最小值.

    因为可以任意次数的交换,所以我们最多交换k次或者交换n的长度次即交换min(len(n), k). 所以可以直接暴力.

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    char s1[16];
    char s2[16];
    char ans[16];
    int len;
    
    void dfs1(int now, int k) {
        int i;
        if (k==0 || now==len) {
        //    if (s1[0] == '0') return ;
            if (strcmp(ans, s1) > 0) 
                strcpy(ans, s1);
            return ;
        }
        if (now == 0) {
            for (i=now+1; i<len; ++i) {
                if (s1[i] < s1[now] && s1[i]!='0') {
                    swap(s1[now], s1[i]);
                    dfs1(now + 1, k-1);
                    swap(s1[now], s1[i]);
                }
            }
        } else {
            for (i=now+1; i<len; ++i) {
                if (s1[i] < s1[now]) {
                    swap(s1[now], s1[i]);
                    dfs1(now + 1, k-1);
                    swap(s1[now], s1[i]);
                }
            }
        }
        dfs1(now+1, k);
    }
    
    void dfs2(int now, int k) {
        int i;
        if (k==0 || now==len) {
        //    if (s2[0] == '0') return ;
            if (strcmp(ans, s2) < 0) 
                strcpy(ans, s2);
            return ;
        }
        for (i=now+1; i<len; ++i) {
            if (s2[i] > s2[now]) {
                swap(s2[now], s2[i]);
                dfs2(now + 1, k-1);
                swap(s2[now], s2[i]);
            }
        }
        dfs2(now+1, k);
    }
    
    int main()
    {
        int t, k;
        scanf("%d", &t);
        while (t--) {
            
            scanf("%s%d", s1, &k);
            len = strlen(s1);
            strcpy(s2, s1);
            
            strcpy(ans, s1);
            dfs1(0, min(k, len));
            printf("%s ", ans);
            
            strcpy(ans, s2);
            dfs2(0, min(k, len));
            printf("%s
    ", ans);
        }
        return 0;
    }
    View Code

    和为K的组合 51Nod - 1268

    给你n和数字 和一个k,问你从n个数字中选若干个数字,这些数字的和是否为k

    因为n最多只有20个.所以直接爆搜.

    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    int n, k;
    int arr[32];
    
    bool cmp(const int &a, const int &b) {
        return a > b;
    } 
    
    bool flag = false;
    
    bool dfs(int deep, int val) 
    {
        if (flag) return true;
        if (val <  0) return false;
        if (val == 0) return flag=true;
        if (deep==n-1) {
            if (val == arr[deep]) return true;
            else return false;
        }
        return dfs(deep+1, val-arr[deep]) || dfs(deep+1, val);
    }
    
    int main()
    {
        int sum;
        while (~scanf("%d%d", &n, &k)) {
            sum = k;
            int i;
            for (i=0; i<n; ++i) {
                scanf("%d", &arr[i]);
                sum -= arr[i];
            }
            sort(arr, arr+n, cmp);
            flag = false;
            if (sum>0 || !dfs(0, k)) printf("No
    ");
            else printf("Yes
    ");
        }
        
        return 0;
    }
    View Code

    BFS大杂烩

    Dungeon Master POJ - 2251 

    给一个起点,一个终点,多个层.问最短路. 直接bfs.

    #include <stdio.h>
    #include <string.h>
    #include <queue>
    
    using namespace std;
    
    int l,n,m;
    
    char map[31][31][31];
    bool vis[31][31][31];
    int dir[] = {1,0,-1,0,1};
    int updw[] = {-1,1};
    
    typedef struct nobe{
        int x;
        int y;
        int l;
        int step;
    }nobe;
    
    
    int bfs(nobe s)
    {
        int i;
        nobe bb,cc;
        queue<nobe> q;
        
        q.push(s);
        memset(vis,0,sizeof(vis));
        while(!q.empty()){
            bb = q.front();
            q.pop();
            
            if(bb.x<0 || bb.y<0 || bb.l<0 || bb.x>=n || bb.y>=m || bb.l>=l) continue;
            if('#' == map[bb.l][bb.x][bb.y]) continue;
            if('E' == map[bb.l][bb.x][bb.y]) return bb.step;
            if(vis[bb.l][bb.x][bb.y]) continue;
            vis[bb.l][bb.x][bb.y] = 1;
            
            for(i=0; i<4; ++i){
                cc.step = bb.step+1;
                cc.l = bb.l;
                cc.x = bb.x+dir[i];
                cc.y = bb.y+dir[i+1];
                q.push(cc);
            }
            for(i=0; i<2; ++i){
                cc.step = bb.step+1;
                cc.l = bb.l + updw[i];
                cc.x = bb.x;
                cc.y = bb.y;
                q.push(cc);
            }    
        }
        return -1;
    }
    
    int main()
    {
        int i,j,z,ans;
        char str[40];
        nobe s;
        while(scanf("%d%d%d",&l,&n,&m) && (l!=0 || n!=0 || m!=0)){
            for(z=0; z<l; ++z){
                for(i=0; i<n; ++i){
                    scanf("%s",str);
                    for(j=0; j<m; ++j){
                        map[z][i][j] = str[j];
                        if('S'==str[j]){
                            s.l = z;
                            s.x = i;
                            s.y = j;
                            s.step = 0;
                        }
                    }
                }
            }
            ans = bfs(s);
            if(-1 == ans){
                printf("Trapped!
    ");
            }else{
                printf("Escaped in %d minute(s).
    ",ans);
            }
        }
        
        return 0;
    }
    View Code

    Catch That Cow POJ - 3278

    给两个数st, ed. 问你st经过至少多少次变换后可以到达ed.  st有以下变化: st+1, st-1, st*2

    还是很裸的bfs.

    但是有个坑我很久的地方是: G++会wa,C++可以A...原因我也不清楚.

    #include <cstdio>
    #include <cstring>
    #include <queue>
    
    using namespace std;
    
    struct nobe {
        int x;
        int step;
        nobe () {}
        nobe (int xx, int tt) : x(xx), step(tt) {}
    };
    
    bool vis[400100];
    
    int bfs(int n, int k) 
    {
        memset(vis, 0, sizeof(vis));
        nobe now(n, 0);
        queue<nobe> q;
        q.push(now);
        while (!q.empty()) {
            now = q.front(); q.pop();
            if (now.x == k) return now.step;
            if (vis[now.x]) continue;
            vis[now.x] = true;
            if (now.x-1>=0 && !vis[now.x-1]) q.push(nobe(now.x-1, now.step+1));
            if (now.x+1<400100&& !vis[now.x+1]) q.push(nobe(now.x+1, now.step+1));
            if (now.x*2<400100&& !vis[now.x*2]) q.push(nobe(now.x*2, now.step+1));
        }
    }
    
    int main()
    {
        int n, k;
        while (~scanf("%d%d", &n, &k)) {
            if (n>=k) printf("%d
    ", n-k);
            else printf("%d
    ", bfs(n, k));
        }
        
        return 0;
    }
    View Code

    不过也有一种bfs不会wa的写法...然而原因我也还是不清楚....

    #include <cstdio>
    #include <cstring>
    #include <queue>
    
    using namespace std;
    
    struct nobe {
        int x;
        int step;
        nobe () {}
        nobe (int xx, int tt) : x(xx), step(tt) {}
    };
    
    int vis[200100];
    
    int bfs(int n, int k) 
    {
        memset(vis, 0x3f, sizeof(vis));
        nobe now(n, 0);
        queue<nobe> q;
        q.push(now);
        while (!q.empty()) {
            now = q.front(); q.pop();
            if (now.x == k) return now.step;
            if (vis[now.x] < now.step) continue;
            vis[now.x] = now.step;
            if (now.x-1>=0) q.push(nobe(now.x-1, now.step+1));
            if (now.x+1<200100) q.push(nobe(now.x+1, now.step+1));
            if (now.x*2<200100) q.push(nobe(now.x*2, now.step+1));
        }
        return -1;
    }
    
    
    int main()
    {
        int n, k;
        while (~scanf("%d%d", &n, &k)) {
            printf("%d
    ", bfs(n, k));
        }
        
        return 0;
    }
    View Code

    然后这道题也可以dp做 ---> 因为st-1可能会影响到要更新的dp答案..所以可以暴力点....多做几次dp..多做几十次dp..最后答案就趋近于正确答案了...

    当然, 也有别的优秀dp. 但是我不会.

     Prime Path  POJ - 3126

    题目我忘记了. 代码也是copy的以前的. 所以直接粘上来.

    #include <cstdio>
    #include <iostream>
    #include <set>
    #include <map>
    #include <queue>
    #include <cstring>
    
    using namespace std;
    
    bool isprime[10000];
    
    void getprime()
    {
        int i, j;
        isprime[0] = isprime[1] = false;
        for (i=2; i<10000; ++i) isprime[i] = true;
        for (i=2; i<10000; ++i) if (isprime[i]) 
            for (j=2*i; j<10000; j+=i) isprime[j] = false;    
    }
    
    bool vis[10000];
    
    struct nobe {
        int num;
        int step;
    };
    
    void bfs(int st, int ed)
    {
        nobe now, tmp;
        queue<nobe> q;
        
        now.num = st;
        now.step = 0;
        q.push(now);
            
        memset(vis, 0 , sizeof(vis));
        vis[st] = true;
        while (!q.empty()) {
            now = q.front(); q.pop();
            
            if (now.num == ed) {
                cout << now.step << endl;
                return ;
            }
            
            tmp.step = now.step + 1;
            int t, pos;
            for (int i=0; i<10; ++i) {
                
                t = now.num / 1000;
                pos = now.num + 1000*i - t*1000;
                if (!vis[pos] && isprime[pos] && pos>1000) {
                    vis[pos] = true;
                    tmp.num = pos;
                    q.push(tmp);
                }
                        
                
                t = now.num / 100 % 10;
                pos = now.num + 100*i - t*100;
                if (!vis[pos] && isprime[pos]) {
                    vis[pos] = true;
                    tmp.num = pos;
                    q.push(tmp);
                }
                
                t = now.num/10%10;
                pos = now.num+ 10*i - t*10;
                if (!vis[pos] && isprime[pos]) {
                    vis[pos] = true;
                    tmp.num = pos;
                    q.push(tmp);
                }
                    
                t = now.num%10;
                pos = now.num+i-t;
                if (!vis[pos] && isprime[pos]) {
                    vis[pos] = true;
                    tmp.num  = pos;
                    q.push(tmp);
                }        
            }
        }
        cout << "Impossible" << endl;
        return ;
    }
    
    
    int main()
    {
    //    freopen("E:\input.txt", "r", stdin);
        int t;
        int i, j, k;
        getprime();
    //    for (i=1; i<100; ++i) if(isprime[i]) printf("%d ", i);
        cin >> t;
        int a, b;
        while (t--) {
            cin >> a >> b;
            bfs(a, b);
        }
        
        return 0;
    }
    View Code

    Pots POJ - 3414

    给你容量为A和B的两个水杯,有三种操作

    1. FILL(i)        fill the pot i (1 ≤ ≤ 2) from the tap;  把水杯水倒掉
    2. DROP(i)      empty the pot i to the drain;    把水倒完
    3. POUR(i,j)    pour from pot i to pot j; after this operation either the pot jis full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j).  把i杯中的水倒到j杯中.

    求出是否可以恰好让一杯水中的水为C.

    如果可以 输出最小路径, 如果不可以输出impossible

    很明显,这个一个bfs+路径记录的题.  我们定义一个nobe fa[A][B][OP]来存路径, A B 表示A杯和B杯中的容量, OP是操作的类型.nobe是bfs的节点.

    然后在推进一个新节点之前,把fa也更新一下.最后找到最小路径则根据当前节点的fa进行回溯就OK.

    (注意,倒水,填水要注意杯中水的多少. 可以剪掉一些枝.)

    #include <queue>
    #include <stack>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define fillb 0
    #define filla 1
    #define atob 2
    #define btoa 3
    #define dropa 4
    #define dropb 5
    
    struct nobe {
        int A;
        int B;
        int step;
        int dir;
        nobe () { }
        nobe (int aa, int bb, int cc, int type) : A(aa), B(bb), step(cc), dir(type) { }
    };
    
    bool vis[128][128];
    nobe fa[128][128][6];
    
    bool bfs(int A, int B, int C) {
        memset(vis, 0, sizeof(vis));
        memset(fa,  0, sizeof(fa));
        queue<nobe> q;
        int a, b, step, dir;
        nobe now(0, 0, 0, 0);
        q.push(now);
        stack<int> st;
        while (!q.empty()) {
            now = q.front(); q.pop();
            a = now.A; b = now.B; step = now.step;
            if (vis[a][b]) continue;
            vis[a][b] = true; 
            if (a==C || b== C) {
                while (now.A || now.B) {
                    st.push(now.dir);
                    now = fa[now.A][now.B][now.dir];
                }
        //        st.push(now.dir);
                printf("%d
    ", step);
                while (!st.empty()) {
                    dir = st.top(); st.pop();
                    switch(dir) {
                    case filla:  printf("FILL(1)
    ");   break;
                    case fillb:  printf("FILL(2)
    ");   break;
                    case atob:   printf("POUR(1,2)
    "); break;
                    case btoa:   printf("POUR(2,1)
    "); break;
                    case dropa:  printf("DROP(1)
    ");   break;
                    case dropb:  printf("DROP(2)
    ");   break;
                    }
                }
                return false;
            }
        
            if (a && !vis[0][b]) {
                q.push(nobe(0, b, step+1, dropa));
                fa[0][b][dropa] = now;
            }
            
            if (b && !vis[a][0]) {
                q.push(nobe(a, 0, step+1, dropb));
                fa[a][0][dropb] = now;
            }
            
            if (a!=A) {
                if (b) {
                    if ((A-a) >= b) {
                        if (!vis[a+b][0]) {
                            q.push(nobe(a+b, 0, step+1, btoa));
                            fa[a+b][0][btoa] = now;
                        }
                    } else {
                        if (!vis[A][b-(A-a)]) {
                            q.push(nobe(A, b-(A-a), step+1, btoa));
                            fa[A][b-(A-a)][btoa] = now;
                        }
                    }
                }
    
                if (!vis[A][b]) {
                    q.push(nobe(A, b, step+1, filla));
                    fa[A][b][filla] = now;
                }
            }
            
            if (b!=B) {
                if (a) {
                    if ((B-b) >= a) {
                        if (!vis[0][a+b]) {
                            q.push(nobe(0, a+b, step+1, atob));
                            fa[0][a+b][atob] = now;
                        }
                    } else {
                        if (!vis[a-(B-b)][B]) {
                            q.push(nobe(a-(B-b), B, step+1, atob));
                            fa[a-(B-b)][B][atob] = now;
                        }
                    }
                }
                
                if (!vis[a][B]) {
                    q.push(nobe(a, B, step+1, fillb));
                    fa[a][B][fillb] = now;
                }
            }
        }
        return true;
    }
    
    int main()
    {
        int A, B, C;
        while (~scanf("%d%d%d", &A, &B, &C)) {
            if (bfs(A, B, C)) printf("impossible
    ");
        } 
        return 0;
    }
    View Code

    Fire Game FZU - 2150

    给一个一些草地,两个孩子分别从其中一个草地开始放火,问你最后火是否能把草地烧完,如果可以输出时间,如果不可以则输出-1.

    注: 火只能在有草地的地方上下左右蔓延. 

    考虑如果有3个及其以上的分开的草地, 答案肯定是-1.

    如果有2个草地,则是两个孩子分别从某点开始放的最小答案.

    如果只有一个草地, 答案还是两个孩子分别从某点开始放的最小答案.

    如果没有草地,答案就是0.

    所以,我们不妨暴力枚举两个草地,从两个草地开始烧火,然后取最小值.如果有答案,那么就是最终答案,如果没有答案,就是没有答案.

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    bool vis[16][16];
    char _m[16][16];
    int n, m, qans;
    
    struct nobe {
        int x;
        int y;
        int step;
        nobe () {}
        nobe (int xx, int yy, int sstep) : x(xx), y(yy), step(sstep) {}
    };
    
    bool isok() {
        int i, j;
        for (i=0; i<n; ++i) 
            for (j=0; j<m; ++j) 
                if (_m[i][j]=='#' && !vis[i][j]) return false;
        return true; 
    }
    
    int bfs(nobe st1, nobe st2) {
        memset(vis, 0, sizeof(vis));
        queue<nobe> q;
        nobe now;
        q.push(st1);
        q.push(st2);
        int x, y, step;
        while (!q.empty()) {
            now = q.front(); q.pop();
            x = now.x; y = now.y; step = now.step;
            
            if (vis[x][y]) continue;
            vis[x][y] = true;
            
            if (isok()) return step;
            
            if (x-1>=0 && _m[x-1][y]=='#' && !vis[x-1][y]) q.push(nobe(x-1, y, step+1));
            if (x+1 <n && _m[x+1][y]=='#' && !vis[x+1][y]) q.push(nobe(x+1, y, step+1));
            if (y-1>=0 && _m[x][y-1]=='#' && !vis[x][y-1]) q.push(nobe(x, y-1, step+1));
            if (y+1 <m && _m[x][y+1]=='#' && !vis[x][y+1]) q.push(nobe(x, y+1, step+1));
        }
        return 0x3f3f3f3f;
    }
    
    int main()
    {
        int num;
        int t, i, j, x, y;
        scanf("%d", &t);
        for (int cas=1; cas<=t; ++cas) {
            scanf("%d%d", &n, &m);
            for (i=0; i<n; ++i) scanf("%s", _m[i]);
            num = 0;
            memset(vis, 0, sizeof(vis));
            int res = 0x3f3f3f3f;
                for (i=0; i<n; ++i) 
                    for (j=0; j<m; ++j) 
                        for (x=0; x<n; ++x) 
                            for (y=0; y<m; ++y) 
                                if (_m[i][j]=='#' && _m[x][y]=='#') 
                                    res = min(res, bfs(nobe(i, j, 0), nobe(x, y, 0)));
            printf("Case %d: %d
    ", cas, res==0x3f3f3f3f ? -1 : res);
        }
        
        return 0;
    }
    View Code

    Fire! UVA - 11624

    好的,又是火..FFFFFFFFFFFFFFFF

    给一个迷宫,火上下左右烧,问人是否可以逃离. (注,有多个起火点!)

    我们可以同时bfs. 让火先行,然后处理地图,把下一秒中要烧的地方标识出来, 然后人就自然不能走这些地方了.

    如果人可以走出来,那么就输出最小答案.

    如果人不能走出来,那么就输出 IMPOSSIBLE

    #include <cstdio>
    #include <cstring>
    #include <queue>
    
    using namespace std;
    
    int n, m;
    char str[1024][1024];
    bool vis1[1024][1024];
    bool vis2[1024][1024];
    
    struct nobe {
        int x;
        int y;
        int type;
        int step;
        nobe () { }
        nobe (int xx, int yy, int tt, int ss) : x(xx), y(yy), type(tt), step(ss) { }
    };
    
    queue<nobe> q;
    
    int bfs(nobe st1) {
        memset(vis1, 0, sizeof(vis1));
        memset(vis2, 0, sizeof(vis2));
        nobe now;
        
        int x, y, type, step;    
        q.push(st1);
        while (!q.empty()) {
            now = q.front(); q.pop();
            x = now.x; y = now.y; step = now.step; type = now.type;
            
             // Fire
            if (type && vis2[x][y]) continue;
            else if (type) vis2[x][y] = true;
            
            if (!type && vis1[x][y]) continue;
            else if (!type) vis1[x][y] = true;
    
            if (type) {
                if (x+1<n && (str[x+1][y]=='.' || str[x+1][y]=='J') && !vis2[x+1][y]) {
                    str[x+1][y] = 'F';
                    q.push(nobe(x+1, y, type, step+1));
                }
                if (x-1>=0 && (str[x-1][y]=='.'|| str[x-1][y]=='J') && !vis2[x-1][y]) {
                    str[x-1][y] = 'F';
                    q.push(nobe(x-1, y, type, step+1));
                }
                if (y+1<m && (str[x][y+1]=='.'|| str[x][y+1]=='J') && !vis2[x][y+1]) {
                    str[x][y+1] = 'F';
                    q.push(nobe(x, y+1, type, step+1));
                }
                if (y-1>=0 && (str[x][y-1]=='.'|| str[x][y-1]=='J') && !vis2[x][y-1]) {
                    str[x][y-1] = 'F';
                    q.push(nobe(x, y-1, type, step+1));
                }
            } else {
                if (x+1==n)  return step;
                if (x-1==-1) return step;
                if (y+1==m)  return step;
                if (y-1==-1) return step;
                
                if (str[x+1][y]=='.' && !vis1[x+1][y]) 
                    q.push(nobe(x+1, y, type, step+1));
                if (str[x-1][y]=='.' && !vis1[x-1][y]) 
                    q.push(nobe(x-1, y, type, step+1));
                if (str[x][y+1]=='.' && !vis1[x][y+1]) 
                    q.push(nobe(x, y+1, type, step+1));
                if (str[x][y-1]=='.' && !vis1[x][y-1]) 
                    q.push(nobe(x, y-1, type, step+1));
            }
        }    
        
        return 0;
    }
    
    int main()
    {
        int t, i, j;
        scanf("%d", &t);
        while (t--) {
            scanf("%d%d", &n, &m);
            while (!q.empty()) q.pop();
            nobe t1, t2;
            for (i=0; i<n; ++i) {
                scanf("%s", str[i]);
                for (j=0; j<m; ++j) {
                    if (str[i][j] == 'J') {
                        t1.x = i; t1.y = j; t1.step = 1; t1.type = 0;    
                    }    
                    else if (str[i][j] == 'F') {
                        t2.x = i; t2.y = j; t2.step = 1; t2.type = 1;
                        q.push(t2);
                    }
                }
            }
            int res = bfs(t1);
            if (res) printf("%d
    ", res);
            else printf("IMPOSSIBLE
    ");
        }
        
        return 0;
    }
    View Code

    迷宫问题  POJ - 3984

    bfs简单的记录路径..这道题数据贼秀.. 直接输出样例答案就可以A.....

    #include<cstdio>
    main(){puts("(0, 0)
    (1, 0)
    (2, 0)
    (2, 1)
    (2, 2)
    (2, 3)
    (2, 4)
    (3, 4)
    (4, 4)");}
    View Code

    非常可乐 HDU - 1495

    题目基本忘了. 和刚才水杯的题一样的. 粘以前的代码.

    #include <stdio.h>
    #include <string.h>
    #include <queue>
    
    using namespace std;
    
    typedef struct nobe{
        int s;
        int n;
        int m;
        int step;
    }nobe;
    
    int vis[102][102][102];
    
    int bfs(nobe start)
    {
        int S,M,N;
        nobe b,c;
        queue<nobe> Q;
        
        S = start.s;
        M = start.m;
        N = start.n;
        
        start.m = start.n = 0;
        start.step = 0;
        Q.push(start);
        memset(vis,0,sizeof(vis));
        while(!Q.empty()){
            b = Q.front();
            Q.pop();
            
            if((b.m==b.n && 0==b.s) || (b.n==b.s && 0==b.m) || (b.m==b.s && 0==b.n) ){
                return b.step;
            }
            
            if(vis[b.s][b.n][b.m]) continue;
            vis[b.s][b.n][b.m] = 1;
            
            b.step++;
            
            c = b;
            //1 to 2
            if(c.s!=0){
                if(c.n!=N){
                    int t = N-c.n;
                    if(t>=c.s){
                        c.n += c.s;
                        c.s = 0;
                    }else{
                        c.n = N;    
                        c.s -= t;
                    }
                    Q.push(c);
                }    
            }
            
            c = b;
            //1 to 3
            if(c.s!=0){
                if(c.m!=M){
                    int t = M-c.m;
                    if(t>=c.s){
                        c.m += c.s;
                        c.s = 0;
                    }else{
                        c.m = M;
                        c.s -= t;            
                    }
                    Q.push(c);
                }
                
            }
            
            c = b;
            //2 to 3
            if(c.n!=0){
                if(c.m!=M){
                    int t = M-c.m;
                    if(t>=c.n){
                        c.m +=c.n;
                        c.n = 0;
                    }else{
                        c.m = M;
                        c.n-=t;        
                    }
                    Q.push(c);
                }
            
            }                
            
            c = b;
            //2 to 1
            if(c.n!=0){
                if(c.s!=S){
                    int t = S-c.s;
                    if(t>=c.n){
                        c.s +=c.n;
                        c.n = 0;
                    }else{
                        c.s = S;
                        c.n-=t;
                    }
                    Q.push(c);
                }    
            }
                    
            c = b;
            //3 to 1
            if(c.m!=0){
                if(c.s!=S){
                    int t = S-c.s;
                    if(t>=c.m){
                        c.s +=c.m;
                        c.m = 0;    
                    }else{
                        c.s = S;    
                        c.m -= t;
                    }
                    Q.push(c);
                }
            }
                    
            c = b;
            //3 to 2
            if(c.m!=0){
                if(c.n!=N){
                    int t = N-c.n;
                    if(t>=c.m){
                        c.n +=c.m;
                        c.m = 0;    
                    }else{
                        c.n = N;
                        c.m -= t;    
                    }
                    Q.push(c);    
                }
            }            
        }
        return -1;
    }
    
    int main()
    {
        int ans;
        nobe start;
        while (scanf("%d%d%d",&start.s,&start.n,&start.m) && (start.m!=0 || start.s!=0 || start.n!=0) ){
            start.step = 0;
            if (start.s&1){
                ans = -1;
            }else{
                ans = bfs(start);
            }
            if (-1==ans){
                printf("NO
    ");
            }else{
                printf("%d
    ",ans);
            }
        }
            
        return 0;
    }
    View Code

    Find a way  HDU - 2612

    两个人, 多个终点,问到达某个终点的路径之和最小. 坑点就是,两个人的起点不能走!! 不能走!!!

    我的做法是bfs2次, 把答案记录在一个二维数组中. 最后取出最小值就是答案.

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <set>
    
    using namespace std;
    
    char _m[204][204];
    
    struct Point {
        int x;
        int y;
        Point () {}
        Point (int xx, int yy) : x(xx), y(yy) {}
        bool operator < (const Point &a) const {
            if (x != a.x) return x < a.x;
            return y < a.y;
        }
        bool operator == (const Point &a) const {
            return x==a.x && y==a.y;
        }
    }ted[1024];
    
    bool vis[204][204];
    int  ans[204][204];
    int  times[204][204];
    
    struct nobe {
        Point pt;
        int step;
        nobe () {}
        nobe (Point ppt, int sstep) : pt(ppt), step(sstep) {}
    };
    
    int bfs(nobe st, int n, int m) {
        memset(vis, 0, sizeof(vis));
        
        nobe now = st;
        queue<nobe> q;
        q.push(now);
        int x, y;
        while (!q.empty()) {
            now = q.front(); q.pop();
            x = now.pt.x; y = now.pt.y;
            
            if (vis[x][y]) continue;
            vis[x][y] = true;
            if (_m[x][y] == '@') {
                ans[x][y] += now.step;
                times[x][y]++;
            }
            if (x-1>=0 && (_m[x-1][y]=='.' || _m[x-1][y]=='@') && !vis[x-1][y]) q.push(nobe(Point(x-1, y), now.step+11));
            if (x+1< n && (_m[x+1][y]=='.' || _m[x+1][y]=='@') && !vis[x+1][y]) q.push(nobe(Point(x+1, y), now.step+11));
            if (y-1>=0 && (_m[x][y-1]=='.' || _m[x][y-1]=='@') && !vis[x][y-1]) q.push(nobe(Point(x, y-1), now.step+11));
            if (y+1< m && (_m[x][y+1]=='.' || _m[x][y+1]=='@') && !vis[x][y+1]) q.push(nobe(Point(x, y+1), now.step+11));
        }
        return 0x3f3f3f3f;
    }
    
    int main()
    {
    //    freopen("E:\input.txt", "r", stdin);
        
        int n, m;
        int i, j, sz;
        while (~scanf("%d%d", &n, &m)) {
        //    memset(ans, 0, sizeof(ans));
            
            nobe  pt1, pt2;
            sz = 0;
            for(i=0; i<n; ++i) {
                scanf("%s", _m[i]);
                for (j=0; j<m; ++j) {
                    if (_m[i][j] == 'Y') {
                        pt1.pt.x = i; pt1.pt.y = j;
                        pt1.step = 0;
                    } else if (_m[i][j] == 'M') {
                        pt2.pt.x = i; pt2.pt.y = j;
                        pt2.step = 0;
                    } else if (_m[i][j] == '@') {
                        ted[sz].x = i; ted[sz].y = j;
                        sz++;
                    }    
                }
            } 
            int res = 0x3f3f3f3f;
            bfs(pt1, n, m);
            bfs(pt2, n, m);
            for (i=0; i<sz; ++i) { 
                if (times[ted[i].x][ted[i].y] == 2) 
                    res = min(ans[ted[i].x][ted[i].y] , res);
                times[ted[i].x][ted[i].y] = 0;
                ans[ted[i].x][ted[i].y]   = 0;
            }
                
            printf("%d
    ",res);
        }
        
        
        return 0;
    }
    View Code
  • 相关阅读:
    python中的os
    文件系统的简单操作
    文件与目录管理
    用户与用户组管理
    基础命令的操作
    linux开机流程
    ansible源码安装、普通用户实现批量控制
    python3中得数据类型
    判断一个字符串中得大写字母,小写字母,数字出现得次数
    Elasticsearch 如何安全加固
  • 原文地址:https://www.cnblogs.com/cgjh/p/9472791.html
Copyright © 2020-2023  润新知