MCS BFS#1 2015年7月30日

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.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值