Problem Mud
FJ每天6点都准时离开家找BESSIE取奶,但是在前一晚上有一场大雨,田地都充满了泥潭,FJ在(0,0)开始, BESSIE在(X,Y) (-500 <= X <= 500; -500 <= Y <= 500).他可以看见所有N(1 <= N
<= 10,000)个泥潭位于点(ai,bi) (-500 <= A_i<= 500; -500 <= B_i <= 500),每个泥潭只出现在他所在的点.
FJ可以上下左右四个方向移动,但不想弄脏他的新鞋,请找一条路到BESSIE位置,且不经过泥潭的最短路径. 注意: 坐标全部按平面坐标系来定.
输入: 第一行: BESSIE位置 X,Y 和 泥潭个数N
以下 2到N+1 行 泥潭位置 A_i , B_I
输出: FJ至少走多少步才到达BESSIE处.
SAMPLE INPUT (file mud.in):
1 2 7
0 2
-1 3
3 1
1 1
4 2
-1 1
2 2
OUTPUT FORMAT:
11
样例说明:
INPUT DETAILS:
Bessie is at (1, 2). Farmer John sees 7 mud puddles, located at (0,
2); (-1, 3); (3, 1); (1, 1); (4, 2); (-1, 1) and (2, 2). Pictorially:
4 . . . . . . . .
3 . M . . . . . .
Y 2 . . M B M . M .
1 . M . M . M . .
0 . . * . . . . .
-1 . . . . . . . .
-2-1 0 1 2 3 4 5
X
OUTPUT FORMAT:
* Line 1: The minimum distance that Farmer John has to travel to reach
Bessie without stepping in mud.
SAMPLE OUTPUT (file mud.out):
11
OUTPUT DETAILS:
The best path for Farmer John is (0, 0); (-1, 0); (-2, 0); (-2, 1);
(-2, 2); (-2, 3); (-2, 4); (-1, 4); (0, 4); (0, 3); (1, 3); and (1,
2), finally reaching Bessie.
4 ******* . . . .
3 * M . * . . . .
Y 2 * . M B M . M .
1 * M . M . M . .
0 ***** . . . . .
-1 . . . . . . . .
-2-1 0 1 2 3 4 5
X
【题目分析】
(后面这一大堆是什么鬼!)这道题经过分析就知道了,很普通的一道宽搜题,给出起点终点以及障碍物位置,找最短路线,很经典嘛!只不过数据方面出现了负数。当然这很容易处理,只需要每个数输进来时都加501就行(对于这道题)。
不过我很奇怪如果走不到怎么办……于是我就弄了一个NO WAY……
【例程】
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,s,m,o,p;
bool num[1005][1005];
int a[5]={1,0,-1,0},b[5]={0,1,0,-1};
int xx=0,yy=0,ll=0,ans=0,ge=0;
struct lj
{
int x,y,l;
};
lj d[1000001];
int main()
{
freopen("mud.in","r",stdin);
freopen("mud.out","w",stdout);
cin>>n>>m>>s;
n+=502;m+=502;
memset(num,true,sizeof(num));
for(int i=0;i<s;++i)
{
cin>>o>>p;
num[o+502][p+502]=false;
}
int H=0,T=0;
d[0].x=502;
d[0].y=502;
d[0].l=0;
while(H<=T)
{
xx=d[H].x;
yy=d[H].y;
ll=d[H].l;
if(xx==n&&yy==m)
{
cout<<d[H].l<<endl;
return 0;
}
for(int i=0;i<4;++i)
{
if(num[xx+a[i]][yy+b[i]])
{
++T;
d[T].x=xx+a[i];d[T].y=yy+b[i];
d[T].l=ll+1;
num[d[T].x][d[T].y]=false;
}
}
++H;
}
cout<<"NO WAY"<<endl;
return 0;
}
小明的游戏
提交文件:game.pas/game.cpp
输入文件:game.in
输出文件:game.out
题目描述:
小明最近喜欢玩一个游戏。给定一个n * m的棋盘,上面有两种格子#和@。游戏的规则很简单:给定一个起始位置和一个目标位置,小明每一步能向上,下,左,右四个方向移动一格。如果移动到同一类型的格子,则费用是0,否则费用是1。请编程计算从起始位置移动到目标位置的最小花费。
输入格式:
输入文件有多组数据。
输入第一行包含两个整数n,m,分别表示棋盘的行数和列数。
输入接下来的n行,每一行有m个格子(使用#或者@表示)。
输入接下来一行有四个整数x1, y1, x2, y2,分别为起始位置和目标位置。
当输入n,m均为0时,表示输入结束。
输出格式:
对于每组数据,输出从起始位置到目标位置的最小花费。每一组数据独占一行。
输入样例: | 输出样例: |
2 2 @# 0 0 1 1 2 2 @@ @# 0 1 1 0 0 0 | 2 0 |
数据规模:
对于20%的数据满足:1 < = n, m <= 10。
对于40%的数据满足:1 < = n, m <= 300。
对于100%的数据满足:1 < = n, m <= 500。
【题目分析】
这道题看起来是一道很简单的搜索,但实际上我们看数据,用深度搜索显然会爆,但是用宽度搜索呢,又好像不太合适。所以就要采用一种特殊的宽搜。
下面讲两种方法。
第一种:迭代法
普通宽搜都是走了以后要标记已用,但是鉴于此题的特殊性,走了以后并不能标记已用,而是要记录下它的最小花费,然后向四周看,如果走到另一个点的最小花费小于那个点的原先花费,那么就改变其花费,并把这个点加进队列,因为可能这个点的花费小了以后,周围的点花费也会变小。这样一直下去,直到每个点的花费都是最小,程序就结束了。
第二种:双队列
这种方法有些类似于之前学的并查集,就是把相连的一样符号都先查找一次,再查找其周围一圈的不同符号……以此类推,第n次时找到了目标位置,答案就是n。
这种方法的实现前提是用双队列,(⊙o⊙)而双队列也有两种方法实现,一是开两个数组,把相同的存到数组一,不同的存到数组二,搜完后把数组二复制到数组一里。
而第二种则是只用一个数组,其中宽搜里的Head指针先放在中间,找到相同的Head就减一,否则尾加一,这样就可以省去开一个数组。
【例程1,迭代】
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,m,x1,x2,y1,y2;
char ch[502][502];
int a[5]={-1,0,1,0},b[5]={0,1,0,-1};
int xx,yy,mm,ll;
int jl;
int money[502][502];
bool bo[502][502];
struct T
{
int x,y;
};
T d[500*500*500];
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
while(true)
{
scanf("%d%d",&n,&m);
if(n==0&&m==0)
return 0;
memset(ch,'.',sizeof(ch));
memset(money,0,sizeof(money));
memset(bo,false,sizeof(bo));
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
cin>>ch[i][j];
bo[i][j]=true;
}
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1++;y1++;x2++;y2++;
int H=0,T=0;
d[0].x=x1;
d[0].y=y1;
bo[x1][y1]=false;
while(H<=T)
{
int ans;
xx=d[H].x;
yy=d[H].y;
for(int i=0;i<4;++i)
{
int nx=xx+a[i],ny=yy+b[i];
ans=money[xx][yy];
if(ch[xx][yy]!=ch[nx][ny])
ans++;
if(money[nx][ny]>ans)
{
money[nx][ny]=ans;
++T;
d[T].x=nx;d[T].y=ny;
continue;
}
if(bo[nx][ny])
{
++T;
d[T].x=nx;d[T].y=ny;
bo[nx][ny]=false;
money[nx][ny]=ans;
continue;
}
}
++H;
}
cout<<money[x2][y2]<<endl;;
}
}
【例程2,双数组】
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,x1,x2,y1,y2;
int a[]={-1,0,1,0},
b[]={0,1,0,-1};
char ch[502][502];
int xx,yy;
int ans;
int H,T,H2=0;
bool bo[502][502],tui;
struct TT
{
int x,y;
};
TT d[2500000],d2[2500000];
void _set()
{
for(int i=0;i<H2;++i)
d[i]=d2[i];
}
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
while(true)
{
scanf("%d%d",&n,&m);
if(n==0&&m==0)
return 0;
memset(ch,'.',sizeof(ch));
memset(bo,false,sizeof(bo));
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
cin>>ch[i][j];
bo[i][j]=true;
}
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1++;y1++;
x2++;y2++;
ans=-1;
H=0;
d[H].x=x1;
d[H].y=y1;
bo[x1][y1]=false;
tui=true;
H2=1;
while(tui)
{
H=0;
T=H2-1;
H2=0;
++ans;
while(H<=T)
{
xx=d[H].x;
yy=d[H].y;
if(xx==x2 && yy==y2)
{
cout<<ans<<endl;
tui=false;
break;
}
for(int i=0;i<4;++i)
{
int nx=xx+a[i],ny=yy+b[i];
if(!bo[nx][ny])
continue;
if(ch[xx][yy]!=ch[nx][ny])
{
d2[H2].x=nx;d2[H2].y=ny; ++H2;
}
else
{
++T;
d[T].x=nx;d[T].y=ny;
bo[nx][ny]=false;
}
}
++H;
}
_set();
}
}
}
【例程3,单数组】
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int x1,x2,y1,y2;
int px[4]={-1,0,1,0},py[4]={0,1,0,-1};
struct Tgame
{
int x;
int y;
int l;
};
Tgame que[1000000];
char ch[501][501];
bool pd[501][501];
int main()
{
freopen("game_pro.in","r",stdin);
freopen("game_pro.out","w",stdout);
int n,m;
while(cin>>n>>m)
{
if(n==0&&m==0) break;
memset(que,0,sizeof(que));
memset(pd,false,sizeof(pd));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>ch[i][j];
}
cin>>x1>>y1>>x2>>y2;
int head=500000;
int tail=500000;
que[head].x=x1;
que[head].y=y1;
que[head].l=0;
pd[x1][y1]=true;
while(head<=tail)
{
if(que[head].x==x2 && que[head].y==y2)
{
cout<<que[head].l<<endl;
break;
}
int xx=que[head].x;
int yy=que[head].y;
int len=que[head].l;
head++;
for(int i=0;i<4;i++)
{
int nx=xx+px[i];
int ny=yy+py[i];
if(nx>=0 && nx<n && ny>=0 && nx<m && !pd[nx][ny])
{
if(ch[nx][ny]==ch[xx][yy])
{
head--;
pd[nx][ny]=true;
que[head].x=nx;
que[head].y=ny;
que[head].l=len;
}
else
{
tail++;
pd[nx][ny]=true;
que[tail].x=nx;
que[tail].y=ny;
que[tail].l=len+1;
}
}
}
}
}
}
好了,这次测试的报告就写这么多。搜索还是一个比较难的课题,所有还是要多加练习啊!