ACM的第二乐章--BFS
bfs和dfs一样,也是以树形搜索形状进行的,只不过dfs是以树根开始一个个的搜索,而bfs则以步数、层次展开搜索,也就是从树根一层层的向外拓展。这种拓展需要的空间一般都是指数级的,所以不能像dfs一样灵活搜索,往往都是在一定的剪枝策略下展开的,因而bfs一般适合求解最优解。
标志性的bfs里会有一个队列,队列里的状态是理解bfs过程的关键,一般来说,队列里存储的是等待拓展的状态,这些等待拓展的状态是很难知道先后关系的,但是队列里的层次、步数的状态肯定是从队头到队尾递增的,往往我们求解的就是这些递增的状态。
Catch That Cow
http://poj.org/problem?id=3278
重判一下就好了, 可以知道,每个点最好就是只进行一次拓展,但每个点第一次拓展后得到的解是最优的,所以当第一次拓展后,就把这个点标记为访问拓展过了。可以知道队列是最多有1000000个状态,空间不会是问题。

#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,当然,题目难在要进行路径搜索。

#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 ,两个差不多一样的。

#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
重判每个点能有的最大时间,不断以最大的拓展。

#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
状态压缩重判,记录每个点每个状态的最小时间。

#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重判

#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

#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; }