POJ 3414 基础搜索 BFS 六

前一段时间看了题面,第一感觉就是自己肯定不会做,今天试了一下,尽然写出来了。

祝贺自己的进步吧~~^_^

 

  POJ 3414  Pot: http://poj.org/problem?id=3414

  题目大意:  给两个尿壶  大小为  A升和B升

  三种操作  : 把A或者B尿壶 倒空

                      把A或者B尿壶灌满

                     把A尿壶的水灌到B壶里面,如果B灌满了,就停止,A的壶剩着等待下一个操作,反过来是一样的。

  问: 怎么个倒法,能最少操作次数,灌出个 C升的水。

        要求输出最小次数,以及  如何操作

 

  求最少次数还好,DFS不方便,BFS最快捷。

  但是怎么输出操作步骤呢?

 

  想了一段时间,我的解决方法是,每时刻,两壶里的水量 i,j ,都存储一个 上一状态的的倒法。 也就是存储,上一状态的i和j,以及倒法(用字母表示)

  用book来标记哪些水量倒出来过了,一旦C升的水倒出来了就进行输出操作。

 

  输出操作我是用递归倒着来解决。最终升的状态存储了上一次倒的状态以及倒法,而上一次的倒的状态,又存储了上上次的状态以及倒法。直到初始状态以后,就可以逐层输出啦。

 

  可能说的有点混。总结一下,我是

用BFS进行搜索最少次数,并同时记录每个状态的最少次数时,对应的上一状态(这里的“”最少“”依靠BFS的特性,不要纠结)。在BFS到了目标水量后,就用递归输出。

 

给出以下代码,不清楚的地方可以问,会更新。

BFS:

 

#include"cstdio"
#include"cstring"
#include"queue"
#include"algorithm"
using namespace std;
#define inf 109
#define loop(x,y,z) for(x=y;x<z;x++)

int a,b,c,sum;
int book[inf];
struct point
{int i,j;
point()
{

}
point(int x,int y)
{
    i=x;j=y;
}
};
struct node
{
    int li,lj;
    char verb;
    int cup;
    int step;
    void set(int i,int j,int k,char c)
    {
        li=i;lj=j;cup=k;verb=c;;
    }
}pos[inf][inf];
queue<point>q;
void init()
{
    while(!q.empty())q.pop();
    memset(pos,-1,sizeof pos);
    memset(book,0,sizeof book);
    sum=0;
}

void print(int i,int j)
{
    char x=pos[i][j].verb;
    int y=pos[i][j].cup;
    if(x=='F')
    {
        printf("FILL(%d)\n",y);
    }
    else if(x=='P')
    {
        int z=(y==1)?2:1;
        printf("POUR(%d,%d)\n",y,z);
    }
    else if(x=='D')
    {
        printf("DROP(%d)\n",y);
    }
}

void dfs(int i,int j)
{
    if(i==0&&j==0)
    {printf("%d\n",sum);return;}
    sum++;
    dfs(pos[i][j].li,pos[i][j].lj);
    print(i,j);//printf("now dfs point is %d %d , and its next point is %d %d\n",i,j,pos[i][j].li,pos[i][j].lj);
}

point fill(int i,int j,int tag)
{
    if(tag==0)i=a;
    else j=b;
    return point(i,j);
}

point drop(int i,int j,int tag)
{
    if(tag==0)i=0;
    else j=0;
    return point(i,j);
}

point pour(int i,int j,int tag)
{
    if(tag==0)
    {
        int t=i+j;
        if(t>b)
        {
            j=b;
            i=t-b;
        }
        else
        {
            j=t;
            i=0;
        }
    }
    else
    {
        int t=i+j;
        if(t>a)
        {
            i=a;
            j=t-a;
        }
        else
        {
            i=t;
            j=0;
        }
    }
    return point(i,j);
}

void bfs()
{
    int i,j,x,y;
    q.push(point(0,0));              //压入首点
    book[0]=1;                       //标记首点
    while(!q.empty())
    {
        point t=q.front();           //取出队首
        q.pop();                     //吐掉
        for(i=0;i<6;i++)
        {
            point tag;               //tag为变化后点
            if(i<2)
            {
                tag=fill(t.i,t.j,i%2);
                x=tag.i;
                y=tag.j;
                if(pos[x][y].li==-1&&pos[x][y].lj==-1)          //如果变化后点未出现过
                {
                    pos[x][y].set(t.i,t.j,i%2+1,'F');           //记录,标记,入队
                    book[x]=book[y]=1;
                    q.push(tag);
                    if(book[c])                                 //若出现目的水量,输出并结束
                    {
                        dfs(tag.i,tag.j);return;
                    }
                }
            }
            else if(i<4)                                       //下同
            {
                tag=drop(t.i,t.j,i%2);
                x=tag.i;
                y=tag.j;
                if(pos[x][y].li==-1&&pos[x][y].lj==-1)
                {
                    pos[x][y].set(t.i,t.j,i%2+1,'D');
                    book[x]=book[y]=1;
                    q.push(tag);
                    if(book[c])
                    {
                        dfs(tag.i,tag.j);return;
                    }
                }
            }
            else
            {
                tag=pour(t.i,t.j,i%2);
                x=tag.i;
                y=tag.j;
                if(pos[x][y].li==-1&&pos[x][y].lj==-1)
                {
                    pos[x][y].set(t.i,t.j,i%2+1,'P');
                    book[x]=book[y]=1;
                    q.push(tag);
                    if(book[c])
                    {
                        dfs(tag.i,tag.j);return;
                    }
                }
            }

        }

    }
    printf("impossible\n");
}

int main()
{
    scanf("%d%d%d",&a,&b,&c);
    init();
    bfs();
    return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值