[Usaco2005 Dec]【Knights of Ni 骑士】
题目描述
贝茜遇到了一件很麻烦的事:她无意中闯入了森林里的一座城堡,如果她想回家,就必须穿过这片由骑士们守护着的森林。为了能安全地离开,贝茜不得不按照骑士们的要求,在森林寻找一种特殊的灌木并带一棵给他们。
当然,贝茜想早点离开这可怕的森林,于是她必须尽快完成骑士们给的任务,贝茜随身带着这片森林的地图,地图上的森林被放入了直角坐标系,并按 x,yx,y 轴上的单位长度划分成了 W \times HW×H ( 1 \leq W,H \leq 10001≤W,H≤1000 )块,贝茜在地图上查出了她自己以及骑士们所在的位置,当然地图上也标注了她所需要的灌木生长的区域。某些区域是不能通过的(比如说沼泽地,悬崖,以及食人兔的聚居地)。在没有找到灌木之前,贝茜不能通过骑士们所在的那个区域,为了确保她自己不会迷路,贝茜只向正北、正东、正南、正西四个方向移动(注意,她不会走对角线)。她要走整整一天,才能从某块区域走到与它相邻的那块区域。
贝茜希望你能帮她计算一下,她最少需要多少天才可脱离这可怕的地方?输入数据保证贝茜一定能完成骑士的任务。
输入输出格式
输入格式
第1行输入2个用空格隔开的整数,即题目中提到的 W,HW,H 。
接下来输入贝茜持有的地图,每一行用若干个数字代表地图上对应行的地形。第1行描述了地图最北的那一排土地;最后一行描述的则是最南面的。相邻的数字所对应的区域是相邻的。如果地图的宽小于或等于40,那每一行数字恰好对应了地图上的一排土地。如果地图的宽大于40,那每行只会给出40个数字,并且保证除了最后一行的每一行都包含恰好40个数字。没有哪一行描述的区域分布在两个不同的行里。
地图上的数字所对应的地形:
0:贝茜可以通过的空地;
1:由于各种原因而不可通行的区域;
2:贝茜现在所在的位置;
3:骑士们的位置;
4:长着贝茜需要的灌木的土地。
输出格式
输出一个正整数,即贝茜最少要花多少天才能完成骑士们给的任务。
输入输出样例
输入样例1
8 4 4 1 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 2 1 1 3 0 4 0 0 0 0 4 1 1 1 0
输出样例1
11
解题思路1
分别以骑士和贝茜为起点广搜,并记录步数(注意以贝茜为起点是不能搜索骑士)。然后循环查找树丛位置,两个相加再与ans取最小值即可。
题解1
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,sx,sy,ex,ey,ans=999999+999999; 4 int mp[1001][1001];//存图 5 int bu[1001][1001][2];//记步数,0为贝茜,1为骑士 6 struct node{ 7 int x; 8 int y; 9 };//坐标 10 queue<node> q; 11 bool flag[1001][1001];//标记 12 int dir[4][2]={0,1,0,-1,1,0,-1,0};//四个方向 13 void bfs(int x,int y,int mode) 14 { 15 q.push((node){x,y}); 16 bu[x][y][mode]=0;//起点0步 17 flag[x][y]=true;//标记 18 while(!q.empty()) 19 { 20 node head=q.front(); 21 q.pop(); 22 for(int i=0;i<4;i++) 23 { 24 int tx=head.x+dir[i][0]; 25 int ty=head.y+dir[i][1]; 26 if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&!flag[tx][ty]&&mp[tx][ty]!=1&&mp[tx][ty]!=3)//判断出界、骑士、标记(因为以骑士为中心搜,骑士也会打标记,所以3这里没有特判) 27 { 28 flag[tx][ty]=true;//标记 29 bu[tx][ty][mode]=bu[head.x][head.y][mode]+1;//记录步数 30 q.push((node){tx,ty});//进队列 31 } 32 } 33 } 34 } 35 inline int read(){//快读,不加过不了 36 int x=0,f=1; 37 char ch=getchar(); 38 while(ch<'0'||ch>'9'){ 39 if(ch=='-') 40 f=-1; 41 ch=getchar(); 42 } 43 while(ch>='0'&&ch<='9'){ 44 x=(x<<1)+(x<<3)+(ch^48); 45 ch=getchar(); 46 } 47 return x*f; 48 } 49 int main() 50 { 51 cin>>m>>n; 52 for(int i=1;i<=n;i++) 53 { 54 for(int j=1;j<=m;j++) 55 { 56 mp[i][j]=read(); 57 if(mp[i][j]==2)//记录贝茜 58 { 59 sx=i; 60 sy=j; 61 } 62 if(mp[i][j]==3)//记录骑士 63 { 64 ex=i; 65 ey=j; 66 } 67 bu[i][j][0]=999999;//初始化 68 bu[i][j][1]=999999; 69 } 70 } 71 bfs(sx,sy,0);//以贝茜为起点开始搜索 72 for(int i=1;i<=n;i++) 73 { 74 for(int j=1;j<=m;j++) 75 { 76 flag[i][j]=0;//初始化 77 } 78 } 79 bfs(ex,ey,1);//以骑士为起点开始搜索 80 for(int i=1;i<=n;i++) 81 { 82 for(int j=1;j<=m;j++) 83 { 84 if(mp[i][j]==4)//是树丛就相加取最优 85 { 86 ans=min(ans,bu[i][j][0]+bu[i][j][1]); 87 } 88 } 89 } 90 cout<<ans; 91 }
解题思路2
先从贝茜开始搜索,搜到树丛时开始向骑士搜,等于树丛是一个中转站,没有打标记操作,都用步数作比较判断是否搜索过。
题解2
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m; 4 int mp[1001][1001];//存图 5 int vis[1001][1001][2];//记录步数 6 int dir[4][2]={0,1,0,-1,1,0,-1,0};//方向 7 struct node{ 8 int x; 9 int y;//坐标 10 int t;//步数 11 bool f;//0为贝茜向树丛搜,1为树丛向骑士搜 12 }; 13 queue<node> q; 14 int ans=0x3f3f3f3f;//初始化 15 inline int read(){//快读,不加过不了 16 int x=0,f=1; 17 char ch=getchar(); 18 while(ch<'0'||ch>'9'){ 19 if(ch=='-') 20 f=-1; 21 ch=getchar(); 22 } 23 while(ch>='0'&&ch<='9'){ 24 x=(x<<1)+(x<<3)+(ch^48); 25 ch=getchar(); 26 } 27 return x*f; 28 } 29 int main() 30 { 31 cin>>m>>n; 32 for(int i=1;i<=n;i++) 33 { 34 for(int j=1;j<=m;j++) 35 { 36 mp[i][j]=read(); 37 if(mp[i][j]==2)//记录起点 38 { 39 q.push((node){i,j,0,0}); 40 } 41 } 42 } 43 memset(vis,0x3f3f3f3f,sizeof(vis));//初始化步数 44 while(!q.empty()) 45 { 46 node head=q.front(); 47 q.pop(); 48 if(mp[head.x][head.y]==3)//搜到终点 49 { 50 ans=min(ans,head.t);//取最小值 51 } 52 for(int i=0;i<4;i++) 53 { 54 int tx=head.x+dir[i][0]; 55 int ty=head.y+dir[i][1]; 56 if(tx<1||tx>n||ty<1||ty>m||mp[tx][ty]==1)continue;//越界或者障碍物 57 if(mp[tx][ty]==3&&!head.f)continue;//贝茜不能搜到骑士 58 bool flag=head.f; 59 if(mp[tx][ty]==4)flag=true;//搜到树丛改变标记 60 if(vis[tx][ty][flag]<=head.t+1)continue;//更优 61 vis[tx][ty][flag]=head.t+1; 62 q.push((node){tx,ty,head.t+1,flag});//进队列 63 } 64 } 65 cout<<ans;//输出步数 66 return 0; 67 } 68