例题1:NYOJ 58(最小步数),保存每一步的步数即可,至于标程中是另外一种算法,后面的讨论个人觉得对这个代码的评价不好,因为标程中涉及到的是另外一种算法,不是说他不会用BFS进行广搜,他只是想告诉你这道题用Floyd-Warshall算法可用,不多说了,纯属个人言谈~~用BFS的时候记得把map放在main里面。
#include<iostream> #include<cstring> #include<queue> using namespace std; int num,dx[4]={0,1,0,-1},dy[4]={-1,0,1,0}; class point{ public: int x,y,step; friend istream& operator>>(istream &input,point &P) { input>>P.x>>P.y; return input; } bool operator==(point &P) const { return x==P.x&&y==P.y; } }Start,End; bool Inside(point p) { return p.x>=0&&p.x<9&&p.y>=0&&p.y<9; } int BFS(int map[9][9]) { queue<point> Q; point New,temp; Q.push(Start); map[Start.x][Start.y]=1; while(!Q.empty()) { temp=Q.front(); Q.pop(); if(temp==End) break; for(int i=0;i<4;i++) { New.x=temp.x+dx[i]; New.y=temp.y+dy[i]; if(Inside(New)&&map[New.x][New.y]==0) { map[New.x][New.y]=1; New.step=temp.step+1; Q.push(New); } } } return temp.step; } int main() { cin>>num; while(num--) { int map[9][9]={ 1,1,1,1,1,1,1,1,1, 1,0,0,1,0,0,1,0,1, 1,0,0,1,1,0,0,0,1, 1,0,1,0,1,1,0,1,1, 1,0,0,0,0,1,0,0,1, 1,1,0,1,0,1,0,0,1, 1,1,0,1,0,1,0,0,1, 1,1,0,1,0,0,0,0,1, 1,1,1,1,1,1,1,1,1 }; cin>>Start>>End; Start.step=0; cout<<BFS(map)<<endl; } return 0; }
下面为标准程序:
#include<iostream> #include<cmath> using namespace std; int mz[9][9]={ 1,1,1,1,1,1,1,1,1, 1,0,0,1,0,0,1,0,1, 1,0,0,1,1,0,0,0,1, 1,0,1,0,1,1,0,1,1, 1,0,0,0,0,1,0,0,1, 1,1,0,1,0,1,0,0,1, 1,1,0,1,0,1,0,0,1, 1,1,0,1,0,0,0,0,1, 1,1,1,1,1,1,1,1,1 }; inline int ABS(int a) { return a>0?a:-a; } int len[10][10][10][10]; const int INF=100000; void FloydWarshall() { for(int i=1;i!=8;i++) for(int j=1;j!=8;j++) for(int k=1;k!=8;k++) for(int l=1;l!=8;l++) if(i==k && j== l) len[i][j][k][l]=0; else if(mz[i][j]==0 && mz[k][l]==0 && ABS(i-k)+ABS(j-l)==1) len[i][j][k][l]=1; else len[i][j][k][l]=INF; int v=49; for(int k=1;k!=8;k++) for(int l=1;l!=8;l++) for(int m=1;m!=8;m++) for(int n=1;n!=8;n++) for(int i=1;i!=8;i++) for(int j=0;j!=8;j++) if(len[m][n][i][j]>len[m][n][k][l]+len[k][l][i][j]) len[m][n][i][j]=len[m][n][k][l]+len[k][l][i][j]; } int main() { FloydWarshall(); int n,a,b,c,d; cin>>n; while(n--) { cin>>a>>b>>c>>d; cout<<len[a][b][c][d]<<endl; } return 0; }
例题2:NYOJ 92,题目不难,就是要注意输入,先输入宽,再输入高。把图外边围一圈不是0的数再BFS搜就可以了,代码:
#include<iostream> #include<queue> #include<cstring> #include<cstdio> using namespace std; const int MAX1=1450; const int MAX2=970; int num,wid,high; int dx[4]={0,1,0,-1},dy[4]={-1,0,1,0}; #define CLR(arr,val) memset(arr,val,sizeof(arr)) int map[MAX2][MAX1]; struct point { int x,y; }Start; queue<point> Q; bool Inside(point p) { return p.x>=0&&p.x<=high+1&&p.y>=0&&p.y<=wid+1; } void BFS(int x,int y) { point New,start; start.x=x,start.y=y; Q.push(start); while(!Q.empty()) { start=Q.front(); Q.pop(); for(int i=0;i<4;i++) { New.x=start.x+dx[i]; New.y=start.y+dy[i]; if(Inside(New)&&map[New.x][New.y]!=0) { map[New.x][New.y]=0; Q.push(New); } } } } int main() { scanf("%d",&num); while(num--) { scanf("%d%d",&wid,&high); CLR(map,-1); for(int i=1;i<=high;i++) for(int j=1;j<=wid;j++) scanf("%d",&map[i][j]); BFS(0,0); for(int i=1;i<=high;i++) { printf("%d",map[i][1]); for(int j=2;j<=wid;j++) printf(" %d",map[i][j]); printf("\n"); } } return 0; }
例题3:NYOJ 284,就是要注意一点,当有砖块的时候,你只能用子弹打掉这块砖块将它做空地方处理,继续BFS,而不能我一打掉这块砖块就直接通过这个地方。
#include<iostream> #include<queue> #include<cstring> #include<cstdio> using namespace std; const int MAX=350; #define CLR(arr,val) memset(arr,val,sizeof(arr)) int n,m,dx[4]={0,1,0,-1},dy[4]={-1,0,1,0},visit[MAX][MAX]; char map[MAX][MAX]; struct point{ point(){x=y=step=0;} point(int a,int b,int c):x(a),y(b),step(c){} bool operator==(point p) const {return x==p.x&&y==p.y;} int x,y,step; }Start,End; queue<point> Q; bool Inside(point p) { return p.x>=0&&p.x<n&&p.y>=0&&p.y<m; } void BFS() { point temp,New; Q.push(Start); visit[Start.x][Start.y]=1; while(!Q.empty()) { temp=Q.front(); if(temp==End) break; Q.pop(); if(map[temp.x][temp.y]=='B') { temp.step++; Q.push(temp); map[temp.x][temp.y]='E'; //只能先把这块砖先打掉,而不能打掉后直接通过这个地方,因为打掉这块砖后要把这个地方当做Empty来看,重新搜索 } else for(int i=0;i<4;i++) { New.x=temp.x+dx[i]; New.y=temp.y+dy[i]; char c=map[New.x][New.y]; if(!visit[New.x][New.y]&&Inside(New)&&c!='S'&&c!='R') { New.step=temp.step+1; Q.push(New); visit[New.x][New.y]=1; } } } if(Q.empty()) printf("-1\n"); else printf("%d\n",temp.step); } int main() { while(scanf("%d%d",&n,&m),n||m) { getchar(); CLR(visit,0); while(!Q.empty()) Q.pop();//不要把这个清空的放在最后面去了,WA了n次啊 for(int i=0;i<n;i++) gets(map[i]); for(int i=0;i<n;i++) for(int j=0;j<m;j++) { if(map[i][j]=='Y') Start.x=i,Start.y=j; if(map[i][j]=='T') End.x=i,End.y=j; } BFS(); } return 0; }
例题4:NYOJ 27(水池数目),这个是要求个数,解释不清楚,直接看代码吧:
#include<iostream> #include<cstring> #include<queue> #include<cstdio> using namespace std; const int MAX=101; #define CLR(arr,val) memset(arr,val,sizeof(arr)) int n,m,total,map[MAX][MAX]; int dx[4]={0,1,0,-1},dy[4]={-1,0,1,0}; struct Point { int x,y; }; bool Inside(Point P) { return P.x>=0&&P.x<n&&P.y>=0&&P.y<m; } void BFS(int x,int y) { queue<Point> Q; Point s,New; s.x=x,s.y=y; Q.push(s); while(!Q.empty()) { s=Q.front(); Q.pop(); for(int i=0;i<4;i++) { New.x=s.x+dx[i]; New.y=s.y+dy[i]; if(Inside(New)&&map[New.x][New.y]==1) { map[New.x][New.y]=0; Q.push(New); } } } total++; } int main() { int Case,value; scanf("%d",&Case); while(Case--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) for(int j=0;j<m;j++) { scanf("%d",&value); map[i][j]=value; } total=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(map[i][j]) BFS(i,j); printf("%d\n",total); } return 0; }
例题5:NYOJ 523(亡命逃窜),没有多大改变,就是变成三维的了,没有什么要注意的,就是数据量比较大,用cin,cout会超时,改成scanf,printf输入输出就可以了。
#include<iostream> #include<cstring> #include<queue> #include<cstdio> using namespace std; const int MAX=51; int A,B,C,Time,map[MAX][MAX][MAX]; int dx[6]={-1,0,1,0,0,0},dy[6]={0,1,0,-1,0,0},dz[6]={0,0,0,0,1,-1}; struct Point { int x,y,z,step; bool operator==(const Point& P) const { return x==P.x&&y==P.y&&z==P.z; } }; Point Start,End; bool Inside(Point P) { return P.x>=0&&P.x<A&&P.y>=0&&P.y<B&&P.z>=0&&P.z<C; } int BFS() { queue<Point> Q; Point s,New; Q.push(Start); map[Start.x][Start.y][Start.x]=1; while(!Q.empty()) { s=Q.front(); Q.pop(); if(s==End&&s.step<=Time) return s.step; for(int i=0;i<6;i++) { New.x=s.x+dx[i]; New.y=s.y+dy[i]; New.z=s.z+dz[i]; if(Inside(New)&&map[New.x][New.y][New.z]==0) { map[New.x][New.y][New.z]=1; New.step=s.step+1; Q.push(New); } } } return 0; } int main() { int Case,flag; scanf("%d",&Case); while(Case--) { scanf("%d%d%d%d",&A,&B,&C,&Time); Start.x=0,Start.y=0,Start.z=0,Start.step=0; End.x=A-1,End.y=B-1,End.z=C-1; for(int i=0;i<A;i++) for(int j=0;j<B;j++) for(int k=0;k<C;k++) { scanf("%d",&flag); map[i][j][k]=flag; } flag=BFS(); if(flag) printf("%d\n",flag); else printf("-1\n"); } return 0; }
嗯,最后一个题型了,马的遍历,POJ 2243(马的遍历),记住加visit[][],剪枝防止超时,找到马的跳跃过程中坐标的变化情况即可。
#include<iostream> #include<cstring> #include<queue> #include<cstdio> using namespace std; const int MAX=10; #define CLR(arr,val) memset(arr,val,sizeof(arr)) int visit[MAX][MAX]; int dx[8]={-2,-1,1,2,2,1,-1,-2},dy[8]={1,2,2,1,-1,-2,-2,-1}; struct Point { int x,y,step; bool operator==(const Point &P) const { return P.x==x&&P.y==y; } }; Point Start,End; bool Inside(Point P) { return P.x>=1&&P.x<9&&P.y>=1&&P.y<9; } int BFS() { queue<Point> Q; Point s,New; Q.push(Start); while(!Q.empty()) { s=Q.front(); Q.pop(); if(s==End) return s.step; for(int i=0;i<8;i++) { New.x=s.x+dx[i]; New.y=s.y+dy[i]; if(Inside(New)&&!visit[New.x][New.y]) { New.step=s.step+1; visit[New.x][New.y]=1; Q.push(New); } } } } int main() { char S[10],E[10]; while(scanf("%s %s",S,E)!=EOF) { CLR(visit,0); Start.x=S[0]-'a'+1,Start.y=S[1]-'0',Start.step=0; End.x=E[0]-'a'+1,End.y=E[1]-'0'; visit[Start.x][Start.y]=1; printf("To get from %s to %s takes %d knight moves.\n",S,E,BFS()); } return 0; }