BFS #1 题解
传送门 :
[ http://acm.hust.edu.cn/vjudge/contest/view.action?cid=84857 ]
(第一次写这样的东西。如版面雷同。纯粹模仿二狗→_→)
Problem A
题目意思:有N层楼,要求从A楼层开始去B楼层。每按一次按钮可以上Ki层或者下Ki层。问到达B楼层最少要按钮.能到达输出最少次数。不能到达输出-1.
思路:采用一般的BFS套路就可以解决。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int N,A,B;
int Floor[205]; //存放:i楼层的ki值
int Check[205]; //检测i楼层是否走过
int Pre[205]; //存放:i楼层是由哪一层楼到达
int number; //统计步数
int Up_Down[2]={ 1, -1 }; //电梯上还是下
bool Can; //能不能找到到达的方法
bool bIsLeagal(int Next ) //判断接下来要走的楼层有没有超过边界
{
if( Next < 1 || Next > N )
return false;
return true;
}
void GetCount(int Index) //计数。从终点回溯找到起点。number++
{
while( Pre[ Index ] != -1 )
{
Index = Pre[ Index ];
number++;
}
}
void bfs()
{
queue<int> check_floor;
memset( Check,0,sizeof(Check));
memset( Pre,0,sizeof( Pre ));
Pre[A] = -1;
Check[A] = true;
check_floor.push ( A );
int Now,Next;
while( !check_floor.empty ())
{
Now = check_floor.front ();
check_floor.pop ();
if( Now == B ) //到达B楼层。退出
{
Can = true;
GetCount( Now ); //得到处理了多少次
return;
}
int i;
for( i = 0; i < 2; i++ )
{
Next = Now + Floor[Now] * Up_Down[i]; //上或下ki层楼后到达的楼层
if( bIsLeagal( Next ) && !Check[Next] ) //如果到达的楼层没有越界。也没有被访问过
{
Pre[Next] = Now; //记下通过哪一层到达这层
Check[Next] = true; //标记更改为访问过
check_floor.push ( Next ); //加入队列
}
}
}
}
int main()
{
while( cin >> N )
{
if( N == 0 ) break;
cin >> A >> B;
Can = false;
number = 0;
memset( Floor,0,sizeof( Floor));
int i;
for( i = 1; i <= N; i++ )
cin>> Floor[i];
bfs();
if( Can )
cout<< number <<endl;
else
cout<<-1<<endl;
}
return 0;
}
Problem B
题目意思:告诉你n,k和n的移动方式。问n要至少移动多少次才能到k。
思路:和上一题差不多。都是简单的bfs
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
int vis[100005]; //标记该位置是否被访问过
int Pre[100005]; //到达该位置的前一位置的坐标
int N,K,number; //计数
using namespace std;
void GetCount( int Index ) //计数。从终点回溯找到起点。number++
{
while( Pre[ Index ] != -1 )
{
Index = Pre[ Index ];
number++;
}
}
bool IsLeagal( int Next ) //判断Next时候越界
{
if( Next < 0 || Next >= 100005 )
return false;
return true;
}
void bfs()
{
queue<int> line;
memset( Pre,0,sizeof(Pre));
memset( vis,0,sizeof(Pre));
vis[ N ] = true;
Pre[ N ] = -1;
line.push ( N );
int Now,next_1,next_2,next_3;
while( !line.empty ())
{
Now = line.front ();
line.pop ();
if( Now == K ) //满足条件。退出
{
return ;
}
next_1 = Now +1; //第一种走法: 走到X+1的位置
if( !vis[next_1] && IsLeagal(next_1) )
{
Pre[next_1] = Now;
vis[next_1] = true;
line.push ( next_1 );
}
next_2 = Now - 1; //第二种走法:走到x- 1 的位置
if( !vis[next_2] && IsLeagal(next_2) )
{
Pre[next_2] = Now;
vis[next_2] = true;
line.push ( next_2 );
}
next_3 = Now * 2; //第三种走法: 走到2*x 的位置
if( !vis[next_3] && IsLeagal(next_3))
{
Pre[next_3] = Now;
vis[next_3] = true;
line.push ( next_3 );
}
}
}
int main()
{
while( cin >> N >> K)
{
number = 0;
bfs();
GetCount( K ); //得出答案
cout<<number<<endl;
}
return 0;
}
Problem C
题目意思:倒水。有S毫升的可以(可认为有一个体积为S的容器),和两个M和N的杯子。问能不能用这些容器能不能平分可乐。能,输出最下次数。不能输出No。
思路:(本人鶸,只能想到这样的笨办法)。3个杯子。就有6种道法。所以每个bfs过去。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int S,N,M;
int NUMBER;
bool Can;
int vis[101][101][101]; //判断这种情况是否被访问过
struct Tri
{
int s;
int n;
int m;
int number;
};
/*满足条件就退出。条件:两个相同(不等于0)的同时另一个等于0*/
bool IsOver( int s,int n,int m )
{
if( (s == m && s != 0 && n == 0 )|| ( s == n && n != 0 && m==0 )|| ( m == n && m !=0 && s == 0 ) )
return true;
return false;
}
/*判断是否越界*/
bool IsLeagal( int s,int n,int m )
{
if( s < 0 || s > S || n < 0 || n > N || m < 0 || m > M )
return false;
return true;
}
void bfs()
{
queue<Tri> Ways;
memset( vis,0,sizeof( vis));
vis[S][0][0] = 1;
Tri Now,Next1,Next2,Next3,Next4,Next5,Next6;
Now.s = S;
Now.n = 0;
Now.m = 0;
Now.number = 0;
Ways.push ( Now );
while( !Ways.empty ())
{
Now.s = Ways.front ().s ;
Now.n = Ways.front ().n ;
Now.m = Ways.front ().m ;
Now.number = Ways.front ().number ;
Ways.pop ();
if( Can )
return;
/* 从第一个杯子到给第二个杯子 */
/* 接着6种都是一个意思。如果能倒满的话。就执行if处理,不能的话就有多少到多少过去*/
if( Now.s > ( N - Now.n) )
{ Next1.s = Now.s - ( N - Now.n);
Next1.n = N;
Next1.m = Now.m;
Next1.number = Now.number + 1;}
else
{ Next1.s = 0;
Next1.n = Now.n + Now.s ;
Next1.m = Now.m;
Next1.number = Now.number + 1;}
/*判断能否访问*/
if( IsLeagal( Next1.s ,Next1.n ,Next1.m ) && !vis[Next1.s ][Next1.n ][Next1.m ])
{
vis[Next1.s ][Next1.n ][Next1.m ] = 1;
/* 判断是否满足条件退出 */
if( IsOver( Next1.s ,Next1.n ,Next1.m ))
{ Can = true;
NUMBER = Next1.number ;
return; }
Ways.push ( Next1 );
}
/* 从第一个杯子到给第三个杯子 */
/* 与上同一个意思。查看第一个解释 */
if( Now.s > ( M - Now.m ) )
{ Next2.s = Now.s - ( M - Now.m );
Next2.n = Now.n;
Next2.m = M;
Next2.number = Now.number + 1;}
else
{ Next2.s = 0;
Next2.n = Now.n;
Next2.m = Now.s + Now.m;
Next2.number = Now.number + 1;}
if( IsLeagal( Next2.s ,Next2.n ,Next2.m ) && !vis[Next2.s ][Next2.n ][Next2.m ])
{
vis[Next2.s ][Next2.n ][Next2.m ] = 1;
if( IsOver( Next2.s ,Next2.n,Next2.m ))
{ Can = true;
NUMBER = Next2.number ;
return; }
Ways.push ( Next2 );
}
/* 从第二个杯子到给第一个杯子 */
/* 与上同一个意思。查看第一个解释 */
if( Now.n > ( S - Now.s ) )
{ Next3.s = S;
Next3.n = Now.n - ( S - Now.s );
Next3.m = Now.m;
Next3.number = Now.number + 1;}
else
{ Next3.s = Now.s + Now.n ;
Next3.n = 0;
Next3.m = Now.m;
Next3.number = Now.number + 1;}
if( IsLeagal( Next3.s ,Next3.n ,Next3.m ) && !vis[Next3.s ][Next3.n ][Next3.m ])
{
vis[Next3.s ][Next3.n ][Next3.m ] = 1;
if( IsOver( Next3.s ,Next3.n ,Next3.m ))
{ Can = true;
NUMBER = Next3.number ;
return; }
Ways.push ( Next3 );
}
/* 从第二个杯子到给第三个杯子 */
/* 与上同一个意思。查看第一个解释 */
if( Now.n > ( M - Now.m ))
{ Next4.s = Now.s ;
Next4.n = Now.n - ( M - Now.m );
Next4.m = M;
Next4.number = Now.number + 1;}
else
{ Next4.s = Now.s ;
Next4.n = 0;
Next4.m = Now.n + Now.m ;
Next4.number = Now.number + 1;}
if( IsLeagal( Next4.s ,Next4.n ,Next4.m ) && !vis[Next4.s ][Next4.n ][Next4.m ])
{
vis[Next4.s ][Next4.n ][Next4.m ] = 1;
if( IsOver( Next4.s ,Next4.n ,Next4.m ))
{ Can = true;
NUMBER = Next4.number ;
return; }
Ways.push ( Next4 );
}
/* 从第三个杯子到给第一个杯子 */
/* 与上同一个意思。查看第一个解释 */
if( Now.m - ( S - Now.s ) )
{ Next5.s = S;
Next5.n = Now.n ;
Next5.m = Now.m - ( S - Now.s );
Next5.number = Now.number + 1;}
else
{ Next5.s = Now.s + Now.m ;
Next5.n = Now.n ;
Next5.m = 0;
Next5.number = Now.number + 1;}
if( IsLeagal( Next5.s ,Next5.n ,Next5.m ) && !vis[Next5.s ][Next5.n ][Next5.m ])
{
vis[Next5.s ][Next5.n ][Next5.m ] = 1;
if( IsOver( Next5.s ,Next5.n ,Next5.m ))
{ Can = true;
NUMBER = Next5.number ;
return; }
Ways.push ( Next5 );
}
/* 从第三个杯子到给第二个杯子 */
/* 与上同一个意思。查看第一个解释 */
if( Now.m > ( N - Now.n ))
{ Next6.s = Now.s;
Next6.n = N;
Next6.m = Now.m - ( N - Now.n );
Next6.number = Now.number + 1;}
else
{ Next6.s = Now.s;
Next6.n = Now.m + Now.n ;
Next6.m = 0;
Next6.number = Now.number + 1;}
if( IsLeagal( Next6.s ,Next6.n ,Next6.m ) && !vis[Next6.s ][Next6.n ][Next6.m ])
{
vis[Next6.s ][Next6.n ][Next6.m ] = 1;
if( IsOver( Next6.s ,Next6.n ,Next6.m ))
{ Can = true;
NUMBER = Next6.number ;
return; }
Ways.push ( Next6 );
}
}
}
int main()
{
while( cin >> S >> N >> M )
{
if( S == 0 && N == 0 && M == 0 ) break;
/* 这部分是在测试 413和431得到不同答案的时候心一横改的。没改之前WA。改完就AC了我也不知道为什么QAQ */
if( N > M )
{
int tmp;
tmp = N;
N =M;
M = tmp;
}
/* 因为容器都是整数。所以S为奇数时,一定不能等分 */
if( S % 2 != 0 )
{
cout<<"NO"<<endl;
continue;
}
Can = false;
bfs();
if( Can )
cout<< NUMBER <<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
后记:在写这道题的时候我的表情是这样的:OAO,QAQ,TwT,XAX.