搜索入门_简单搜索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\n",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("\n");
            }
        } else printf("IMPOSSIBLE\n");
    }
    
    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] = '\0'; 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\n", 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\n", 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\n", 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\n");
        else printf("Yes\n");
    }
    
    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!\n");
        }else{
            printf("Escaped in %d minute(s).\n",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", n-k);
        else printf("%d\n", 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\n", 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\n", step);
            while (!st.empty()) {
                dir = st.top(); st.pop();
                switch(dir) {
                case filla:  printf("FILL(1)\n");   break;
                case fillb:  printf("FILL(2)\n");   break;
                case atob:   printf("POUR(1,2)\n"); break;
                case btoa:   printf("POUR(2,1)\n"); break;
                case dropa:  printf("DROP(1)\n");   break;
                case dropb:  printf("DROP(2)\n");   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\n");
    } 
    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\n", 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\n", res);
        else printf("IMPOSSIBLE\n");
    }
    
    return 0;
}
View Code

 

迷宫问题  POJ - 3984

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

#include<cstdio>
main(){puts("(0, 0)\n(1, 0)\n(2, 0)\n(2, 1)\n(2, 2)\n(2, 3)\n(2, 4)\n(3, 4)\n(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\n");
        }else{
            printf("%d\n",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\n",res);
    }
    
    
    return 0;
}
View Code

 

posted @ 2018-08-14 09:54  过路人1998  阅读(249)  评论(0编辑  收藏  举报