例题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;
}