ACM的第二乐章--BFS

bfs和dfs一样,也是以树形搜索形状进行的,只不过dfs是以树根开始一个个的搜索,而bfs则以步数、层次展开搜索,也就是从树根一层层的向外拓展。这种拓展需要的空间一般都是指数级的,所以不能像dfs一样灵活搜索,往往都是在一定的剪枝策略下展开的,因而bfs一般适合求解最优解。

标志性的bfs里会有一个队列,队列里的状态是理解bfs过程的关键,一般来说,队列里存储的是等待拓展的状态,这些等待拓展的状态是很难知道先后关系的,但是队列里的层次、步数的状态肯定是从队头到队尾递增的,往往我们求解的就是这些递增的状态。

Catch That Cow

http://poj.org/problem?id=3278

重判一下就好了, 可以知道,每个点最好就是只进行一次拓展,但每个点第一次拓展后得到的解是最优的,所以当第一次拓展后,就把这个点标记为访问拓展过了。可以知道队列是最多有1000000个状态,空间不会是问题。

View Code
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
int vis[1000000];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)==2)
    {
        queue<int>que;
        queue<int>dis;
        int ans = 100000000;
        que.push(n);
        dis.push(0);
        memset(vis,0,sizeof(vis));
        vis[n]=0;
        
        while(!que.empty()){
            int k = que.front();
            int d = dis.front();
            
            que.pop();
            dis.pop();
            
            if(k==m){ if(d < ans) ans = d; }
            else if( k > m){ if(k - m + d < ans ){ ans = k - m + d;  }}
            else if(d < ans) {
                if(!vis[k*2]){
                 que.push(k*2);  
                 dis.push(d+1); 
                 vis[k*2]=1;
                }
                if(!vis[k+1]){
                 que.push(k+1);
                 dis.push(d+1); 
                 vis[k+1]=1;
                }
                if(k>0&&!vis[k-1]){
                    que.push(k-1);
                     dis.push(d+1);
                     vis[k]=1;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

Find The Multiple

http://poj.org/problem?id=1426

简单bfs,这个可能和数学分析有点关系,由于这个数并不大(<=200),所以可以以这个数的余数为状态来进行bfs,所求得的数最多是400,当然,题目难在要进行路径搜索。

View Code
#include<stdio.h>
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;

struct nd{
    int res,pre,cur;
}as[10000000];

void dfs(int x)
{
    if(as[x].pre==-1){
        printf("1");
        return ;
    }
    dfs(as[x].pre);
    printf("%d",as[x].cur);
}

int main()
{
    int n;
    while(scanf("%d",&n)==1){
        if(!n)break;
        if(n==1){ puts("1"); continue; }
        
        int ts = 0,te = 1;
        as[ts].res = 1;
        as[ts].pre = -1;
        as[ts].cur = 1;
        
        while(ts<te){
            int res = as[ts].res;
            
            as[te].cur = 0;
            as[te].pre = ts;
            as[te].res = (as[ts].res * 10) % n;
            if(!as[te].res)break;
            ++te;
            
            as[te].cur = 1;
            as[te].pre = ts;
            as[te].res = (as[ts].res * 10 + 1) % n;
            if(!as[te].res)break;
            ++te;
            
            ++ts;
        }
        
        dfs(te);
        puts("");
    }return 0;
}

Prime Path

http://poj.org/problem?id=3126

建好图后,可以bfs,也可以spfa ,两个差不多一样的。

View Code
#include<stdio.h>
#include<string.h>
#include<set>
#include<queue>
#include<vector>
#include<iostream>
#include<iterator>
using namespace std;
struct nd{
    int num,dis;
};

vector<int>plist[100000];
int vis[100000];
bool isprime(int x)
{
    for(int i = 2; i <= x / 2; ++ i) if(x % i == 0)return false;
    return true;
}
int main()
{
    int n,m,t;
    char str[5];
    
    for(int i = 1000; i < 10000; ++ i) if(isprime(i))vis[i] = 1;
    
    for(int k = 1000; k < 10000; ++ k)if(vis[k]){
        for(int j = 0; j < 4; ++ j){
            for(int i = 0; i < 10; ++ i){
                sprintf(str,"%d",k);
                str[j] = i + '0';
                sscanf(str,"%d",&t);
                if(vis[t]) plist[k].push_back(t);
            }
        }
        
    }
    
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        
        queue<struct nd>que;
        struct nd tmp;
        tmp.num = n;
        tmp.dis = 0;
        int dis = 0;
        que.push(tmp);
        
        memset(vis,0,sizeof(vis));
        vis[n]=1;
        if(n!=m)
        while(!que.empty()){
            struct nd as = que.front();
            que.pop();
            
            int k = as.num,i;
            tmp.dis = as.dis + 1;
            for(i = 0;  i < plist[k].size(); ++ i){
                tmp.num = plist[k][i];
                if(tmp.num == m){ dis = tmp.dis; break; }
                if(!vis[tmp.num]){
                    que.push(tmp);
                    vis[tmp.num]=1;
                }
            }
            if(i!=plist[k].size())break;
        }
        printf("%d\n",dis);
    }
    return 0;
}

Nightmare

http://acm.hdu.edu.cn/showproblem.php?pid=1072

重判每个点能有的最大时间,不断以最大的拓展。

View Code
#include <stdio.h>
#include <iostream>
#include <queue>
#include <string.h>
#include <stdlib.h>

using namespace std;

struct nd{
    int x,y,t,st;
};

int hash[10][10];
int as[10][10];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int n,m,si,sj,di,dj;

int bfs()
{
    nd tmp;
    tmp.x = si;
    tmp.y = sj;
    tmp.t = 6;
    tmp.st = 0;
    
    queue<nd>que;
    que.push(tmp);
    memset(hash,0,sizeof(hash));
    hash[si][sj] = 6;
    
    while(!que.empty()){
        tmp = que.front(); que.pop();
        int xx = tmp.x;
        int yy = tmp.y;
        int t = tmp.t - 1;
        int st = tmp.st + 1;
        
        for (int i = 0; i < 4; i++){
            int x = xx + dx[i];
            int y = yy + dy[i];
            tmp.x = x;
            tmp.y = y;
            tmp.st = st;
            
            if(x<0 || x==n || y<0 || y==m || !as[x][y])continue;
            
            if (as[x][y]==3){ return st; }
            
            if(as[x][y]==4&&hash[x][y]<6){
                hash[x][y] = 6;
                tmp.t = 6;
                que.push(tmp);
            }
            
            if ((t>1)&&(t>hash[x][y])){
                hash[x][y] = t;
                tmp.t = t;
                que.push(tmp);
            }
        }
    }
    return -1;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d %d",&n,&m);
        for (int i=0; i<n; i++) for (int j=0; j<m; j++){ scanf("%d",&as[i][j]); if(as[i][j]==2){ si=i; sj=j; } }
        printf("%d\n",bfs());
    }return 0;
}

胜利大逃亡(续)

http://acm.hdu.edu.cn/showproblem.php?pid=1429

状态压缩重判,记录每个点每个状态的最小时间。

View Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <queue>
using namespace std;

struct nd{
    int key,st;
    int x,y;
};

int hash[1<<11][30][30];
char as[30][30];
int sum[1<<13];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int n,m,t;
int si,sj;

int bfs()
{
    nd ps,qs;
    queue<nd>que;
    
    ps.x = si;
    ps.y = sj;
    ps.key = 0;
    ps.st = 0;
    que.push(ps);
    as[si][sj] = '.';
    memset(hash,0,sizeof(hash));
    hash[0][si][sj]=1;
    
    while(!que.empty())
    {
        qs = que.front(); que.pop();
        if(qs.st>t)break;
        for(int i = 0; i < 4; ++ i){
            ps.x = qs.x + dx[i];
            ps.y = qs.y + dy[i];
            ps.st = qs.st + 1;
            ps.key = qs.key;
            
            if(ps.x<0 || ps.x==n || ps.y<0 || ps.y==m || as[ps.x][ps.y]=='*' || ps.st == t || hash[ps.key][ps.x][ps.y]) continue;
            
            if(as[ps.x][ps.y]=='^') return ps.st;
            if(as[ps.x][ps.y]>='A'&&as[ps.x][ps.y]<='J'){ 
                if(ps.key&(1<<(as[ps.x][ps.y]-'A'))){
                    hash[ps.key][ps.x][ps.y]=1; 
                    que.push(ps);
                } 
            }else if(as[ps.x][ps.y]>='a'&&as[ps.x][ps.y]<='j'){
                 ps.key |= (1<<(as[ps.x][ps.y]-'A')); 
                 que.push(ps); 
                 hash[ps.key][ps.x][ps.y]=1;
            }else if(as[ps.x][ps.y]=='.'){
                 hash[ps.key][ps.x][ps.y]=1; 
                 que.push(ps); 
            }
        }
        
    }
    return -1;
}

int main()
{
    for(int i = 1; i < (1<<12); ++ i) sum[i] = sum[i>>1] + i % 2;
    while(scanf("%d %d %d",&n,&m,&t)==3)
    {
        for(int i = 0; i < n; ++ i){ scanf("%s",as[i]); for(int j = 0; j < m; ++j)if(as[i][j]=='@'){ si = i; sj = j; }}
        printf("%d\n",bfs());
    }return 0;
}

魔板

http://acm.hdu.edu.cn/showproblem.php?pid=1430

先打表,映射一下,cantor重判

View Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
struct nd{
    int stat,op,pre;
}que[50000];

int fac[]={1,1,2,6,24,120,720,5040,40320};
int vis[50000];
char str[10];
char tmp[10];

int cantor()
{
    int ans=0,k;
    for(int i = 0; i < 8; ++ i){
        k = 0;
        for(int j = i + 1; j < 8; ++ j) if(tmp[j]<tmp[i])++k;
        ans += k * fac[8-i-1];
    }
    return ans + 1;
}

void op0()
{
    for(int i = 0; i < 8; ++ i) tmp[7-i] = str[i];
}

void op1()
{
    tmp[0]=str[3]; tmp[1]=str[0]; tmp[2]=str[1]; tmp[3]=str[2];
    tmp[4]=str[5]; tmp[5]=str[6]; tmp[6]=str[7]; tmp[7]=str[4]; tmp[8]=0;
}

void op2()
{
        strcpy(tmp,str);
        tmp[9]=str[5];tmp[5]=tmp[2];tmp[2]=tmp[1];
        tmp[1]=tmp[6];tmp[6]=tmp[9];tmp[8]=0;
}
char s[10],t[10];

void dfs(int x)
{
    if(que[x].pre==-1)return ;
    dfs(que[x].pre);
    printf("%c",que[x].op+'A');
}
void bfs()
{
    int ts=1,te=2,k,d;
    strcpy(s,"12345678");
    memset(vis,0,sizeof(vis));
    sscanf(s,"%d",&k);

    que[1].pre = -1;
    que[1].op = -1;
    que[1].stat = k;
    strcpy(tmp,s);
    k = cantor();
    vis[k] = 1;
    
    while(ts<te){
        k = que[ts].stat;
        
        sprintf(str,"%d",k);
        op0();
        int g = cantor();
        if(!vis[g]){
            sscanf(tmp,"%d",&k);
            que[te].op = 0;
            que[te].pre = ts;
            que[te].stat = k;
            vis[g] = te;
            ++te;
        }
        
        op1();
        g = cantor();
        if(!vis[g]){
            sscanf(tmp,"%d",&k);
            que[te].op = 1;
            que[te].pre = ts;
            que[te].stat = k;
            vis[g] = te;
            ++te;
        }
        
        op2();
        g = cantor();
        if(!vis[g]){
            sscanf(tmp,"%d",&k);
            que[te].op = 2;
            que[te].pre = ts;
            que[te].stat = k;
            vis[g] = te;
            ++te;
        }
        ++ts;
    }
}


void solve()
{
    char ss[10],tt[10];
    int k = 0;
    for(int i = 0; i < 8; ++ i) ss[s[i]-'0'] = i + 1;
    for(int i = 0; i < 8; ++ i) tt[i] = ss[t[i]-'0'] + '0';
    tt[8]=0;
    strcpy(tmp,tt);
    k = cantor();
    dfs(vis[k]);
    puts("");
}
int main()
{
    bfs();
    for(;scanf("%s%s",s,t)==2;solve());
    return 0;
}

单词联想

http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1308

View Code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<vector>
#include<map>
#include<string>
using namespace std;
int n,ok;
char s[20],t[20];
char fr[100][100],de[100][100];
char as[5000000][80];
char bs[5000000][80];


int bfs()
{
    int ts=0,te=1,ks=0,ke=1;
    int i,j,k,st,flag;
    char so[100],*p,to[100],*q,*tp;
    map<string,int>hashas;
    map<string,int>hashbs;
    
    strcpy(as[ts],s);
    strcpy(bs[ks],t);
    hashas[s]=0;
    hashbs[t]=0;
    while(ts<te||ks<ke){             
               if(ts<te){         //正向
                 st=hashas[as[ts]]+1;
                 strcpy(so,as[ts]);
                 ++ts;
                 for(i=0; i<n; i++){
                      tp=so;
                      while((p=strstr(tp,fr[i]))!=NULL){
                          tp=p+strlen(fr[i]);
                          if( st<9 ){
                              for(j=0,q=so; *q; q++ ){
                                             if( q==p ){
                                                  q+=strlen(fr[i])-1;
                                                  for( k=0; de[i][k]; k++ ) 
                                                       to[j++]=de[i][k]; 
                                             }
                                             else to[j++]=*q;
                              }
                          //    if( j>=50 ) continue;
                              to[j]=0;
                              if(strcmp(to,t)==0)   return st;
                              string str(to);
                              if( hashbs.find(str)!=hashbs.end()){
                                    return hashbs[str]+st;
                                }
                              if( hashas.end()==hashas.find(str) ){
                                  hashas[str]=st;
                                  strcpy(as[te],to);
                                  te++;
                              }
                          }
                      }
                 }
                }
              if(ks<ke){             //反向
                 st=hashbs[bs[ks]]+1;
                 strcpy(so,bs[ks]);
                 ks++;
                 for(i=0; i<n; i++){
                      tp=so;
                      while((p=strstr(tp,de[i]))!=NULL){
                          tp=p+strlen(de[i]);
                          if( st<9 ){
                              for(j=0,q=so; *q; q++ ){
                                             if( q==p ){
                                                  q+=strlen(de[i])-1;
                                                  for( k=0; fr[i][k]; k++ ) 
                                                       to[j++]=fr[i][k]; 
                                             }
                                             else to[j++]=*q;
                              }
                              if( j>=50 ) continue;
                              to[j]=0;
                              if(strcmp(to,s)==0)   return st;
                              string str(to);
                              if( hashas.find(str)!=hashas.end()){
                                    return hashas[str]+st;
                                }
                              if( hashbs.end()==hashbs.find(str) ){
                                  hashbs[str]=st;
                                  strcpy(bs[ke],to);
                                  ke++;
                              }
                          }
                      }
                 }
                }
    }
    return -1;
}
int main()
{
    int i,j,k;
    while(scanf("%d",&n)==1)
    {
                    scanf("%s%s",s,t);
                    for( i=0; i<n; i++ ) scanf("%s%s",fr[i],de[i]);
                    if( strcmp(s,t)==0 ){ puts("0"); continue; }
                    k=bfs();
                    if(k<0||k>8)printf("Impossible\n");
                    else printf("%d\n",k);  
    }return 0;
}

posted on 2012-06-21 09:36  aigoruan  阅读(188)  评论(0)    收藏  举报

导航