UVa 10603 Fill( BFS + 判重)

隐式图搜索是最难受的题目之一,但是一般情况下,如果是隐式图搜索的话,都要记录状态,都会有一个状态的转移。

比如这道题,其实状态是只有第三个杯子里面有装满水,第一和第二个杯子里面都是空,那么这个状态可以转移的话,只能有两个方向的转移。第一是想第一杯子倒水,第二是向第二个杯子倒水,那无论是那种转移,只要这个状态曾经存在过,那么这个状态能转移到的状态就已经遍历过,并且每个状态都要有一个唯一的标识,可以通过这个标识来确认这个状态是否已经存在过!如果存在过,就不要再对这个状态进行转移了。所以对于隐式图的搜索,最重要的是怎么记录状态,以及分析状态可以转移的方向。

那么这道题,对于一个状态,一共最多有6种转移的方向,最少是没有可以转移的

具体分下,看一下BFS函数

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
using namespace std;

const int N = 2100000;
const int INF = 0x3fffffff;
map <int , int> mp;
int a, b, c, d;
int na, nb, nc, nd;
int T, ans, dx, di;
struct node{
    int a, b, c, ans;
}No;
queue<node> q;

void insert( int tmp, node x ) {
    if ( !mp.count(tmp) ) {
        mp[tmp] = x.ans;
        q.push( x );
    }
}
int computes( node x ) {
    return x.a*1000000+x.b*1000+x.c;
}
void change( int &x, int &y ) {
    int tmp = x;
    x = y;
    y = tmp;
}
bool judge ( node u ) {
    if ( dx > abs( u.a - d ) ) {
        dx = abs( u.a - d );
        ans = u.ans;
        di = u.a;
    }
    if ( dx > abs( u.b - d ) ) {
        dx = abs( u.b - d );
        ans = u.ans;
        di = u.b;
    }
    if ( dx > abs( u.c - d ) ) {
        dx = abs( u.c - d );
        ans = u.ans;
        di = u.c;
    }
    if ( dx == 0 ) {
        //printf("%d %d %d %d \n", u.a, u.b, u.c, u.ans);
        return 1;
    }
    return 0;
}
void BFS()
{
    mp[c] = 0;
    No.a = 0, No.b = 0, No.c = c, No.ans = 0;
    q.push( No );
    while ( !q.empty() ) {
        node u = q.front(); q.pop();
        int x, tmp;
        if ( judge( u ) ) break;
        //从a往出到
        if ( u.a > 0 ) {
            if ( u.b < b ) {    //pour into b
                tmp = min( u.a, b - u.b );
                No.a = u.a - tmp, No.b = u.b + tmp, No.c = u.c, No.ans = u.ans + tmp;
                tmp = computes( No );
                insert( tmp, No );
            }
            if ( u.c < c ) {   //pour into c
                tmp = min( u.a, c - u.c );
                No.a = u.a - tmp; No.b = u.b; No.c = u.c + tmp, No.ans = u.ans + tmp;
                tmp = computes( No ); 
                insert( tmp, No );
            }
        }
        //从b往出倒
        if ( u.b > 0 ) {
            if ( u.a < a ) {
                tmp = min( u.b, a - u.a );
                No.b = u.b - tmp, No.a = u.a + tmp, No.c = u.c, No.ans = u.ans + tmp;
                tmp = computes( No );
                insert( tmp, No );
            }
            if ( u.c < c ) {
                tmp = min( u.b, c - u.c );
                No.b = u.b - tmp, No.c = u.c + tmp, No.a = u.a, No.ans = u.ans + tmp;
                tmp = computes( No );
                insert( tmp, No );
            }
        }
        //从c往出倒
        if ( u.c > 0 ) {
            if ( u.a < a ) {
                tmp = min( u.c, a - u.a );
                No.c = u.c - tmp, No.a = u.a + tmp, No.b = u.b, No.ans = u.ans + tmp;
                tmp = computes( No );
                insert( tmp, No );
            }
            if ( u.b < b ) {
                tmp = min( u.c, b - u.b );
                No.c = u.c - tmp, No.b = u.b + tmp, No.a = u.a, No.ans = u.ans + tmp;
                tmp = computes( No );
                insert( tmp, No );
            }
        }
    }
}
int main()
{
    scanf("%d", &T);
    while ( T-- ) {
        scanf("%d%d%d%d", &a, &b, &c, &d);
        mp.clear();
        dx = INF;
        while ( !q.empty() ) q.pop();
        BFS();
        printf("%d %d\n", ans, di);
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值