UVA 10603 FILL 隐式图搜索

来源:互联网 发布:笔记本触摸屏关闭软件 编辑:程序博客网 时间:2024/06/05 02:24

题意:有三个杯子,每个杯子所装水的容量为A,B,C,第三个杯子是的水满的,其他杯子都是空的。给出目标容量D,希望用最少的倒水量使其中的某个杯子所装水的量为D。如果无法达到目标容量,那就求出尽可能靠近目标容量的D‘需要的最少倒水量。

思路:隐式图搜索。我们将三个杯子现在的实际装水量和倒水量的总和作为一个状态。因为这里要求出的是倒水量最少的方案,而不是倒水次数最少的方案,正常的bfs的方法就不行了。这里我们需要将bfs中的队列换成优先队列,每次取出倒水量最少的状态进行扩展。

注意:对于这样的暴力搜索,我们要考虑对应的算法是否高效,我们就要计算搜索节点的个数。对于这道题,我们可以得到,因为前后三个杯子总的水量是没有发生变化的,所以只有两个杯子的水量是自由变量,所以整个状态数为:201 * 201 = 40401,这是相当小的状态。所以这样搜索是非常高效的。

          同时,对于不同的要求,我们需要不同的搜索策略。如果只是求最少倒水次数,对应状态转移图中,状态转移的代价为1.只需正常的bfs即可。而本题是要求最少的倒水量,对应在状态转移图中,状态转移的代价是由当前的状态决定的,而求出这种情况下的“最短路”就需要利用优先队列了。

代码如下:

#include <cstdio>#include <algorithm>#include <cstring>#include <queue>using namespace std;const int MAX = 210;int A,B,C,D;bool vis[MAX][MAX];int ans[MAX];int cap[MAX];struct node{    int v[3];    int dist;    node(){}    node(int aa, int bb, int cc,int dd):dist(dd){        v[0]=aa,v[1]=bb,v[2]=cc;    }    bool operator < (const node & rhs) const{        return dist > rhs.dist;    }};int main(void){    //freopen("input.txt","r",stdin);    int T;    scanf("%d",&T);    while(T--){        scanf("%d%d%d%d",&A,&B,&C,&D);        cap[0] = A, cap[1] = B, cap[2] = C;        memset(vis,0,sizeof(vis));        memset(ans,0x3f,sizeof(ans));        priority_queue<node> Q;        Q.push(node(0,0,C,0));        while(!Q.empty()){            node t = Q.top();Q.pop();            if(vis[t.v[0]][t.v[1]]) continue;            vis[t.v[0]][t.v[1]] = true;            for(int i = 0; i < 3; ++i){                int d = t.v[i];                ans[d] = min(ans[d],t.dist);            }            if(ans[D] != 0x3f3f3f3f) break;            for(int i = 0; i < 3; ++i){                for(int j = 0; j < 3; ++j){                    if(j != i){                        if(t.v[i] == 0 || t.v[j] == cap[j]) continue;                        int amo  = min(cap[j], t.v[i] + t.v[j]) - t.v[j];                        node p = t;                        p.dist += amo;                        p.v[i] -= amo, p.v[j] += amo;                        Q.push(p);                    }                }            }        }        for(int i = D; i >= 0; --i){            if(ans[i] != 0x3f3f3f3f){                printf("%d %d\n",ans[i],i);                break;            }        }    }    return 0;}


0 0
原创粉丝点击