倒水问题(Fill,UVa 10603)

原创 2015年11月19日 17:04:48

原题链接

分析:由于有三个杯子,每个杯子中的水量可能不同,假设水量分别为a,b,c,则水量a,b,c就对应一种存在状态,则题目可以抽象为从初始状态0,0,c开始寻找一种最优的路径(倒水量最少)使之达到目标状态(其中一个杯子水量为d(d'))。因此具体做法就是用BFS从初始状态(0,0,c)开始枚举每种状态,直至达到目标状态即可。

PS:此题中还存在一些小细节,由于有三个杯子,因此状态共有(a+1)*(b+1)*(c+1)种可能,但是初始水量是一定的,所以只需要判断前两个杯子的状态就可以确定整个状态;

还有就是优先队列的使用,重载<运算符使之先判断水量最少的状态可以减少枚举次数。

<strong><span style="font-size:18px;">#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<map>
#include<cmath>
#include<sstream>
#include<queue>
#include<cctype>
using namespace std;
typedef long long ll;
#define MAX 205
// 定义状态变量
struct Node {
        int v[3],dist;
        // 重载<运算符使队首为队列中dist最小值元素
        bool operator < (const Node& rhs) const {
                return dist > rhs.dist;
        }
};
int vis[MAX][MAX],cap[3],ans[MAX];
// 更新水量为d时的最优解
void update_ans(const Node& u) {
        for(int i=0;i<3;i++) {
                int d = u.v[i];
                if(ans[d] < 0 || ans[d] > u.dist) ans[d] = u.dist;
        }
}
void solve(int a,int b,int c,int d) {
        cap[0] = a;cap[1] = b;cap[2] = c;
        memset(vis,0,sizeof(vis));
        memset(ans,-1,sizeof(ans));
        priority_queue<Node> q;
        Node start;
        // 初始化初始状态
        start.dist = 0;
        start.v[0] = start.v[1] = 0;
        start.v[2] = c;
        q.push(start);
        vis[0][0] = 1;
        while(!q.empty()) {
                Node u = q.top();q.pop();
                update_ans(u);
                if(ans[d] >= 0) break;
                // 枚举状态
                for(int i=0;i<3;i++)
                for(int j=0;j<3;j++)
                if(i != j) {
                        if(u.v[i] == 0 || u.v[j] == cap[j]) continue;
                        int amount = min(cap[j],u.v[i] + u.v[j]) - u.v[j];
                        Node u2;
                        memcpy(&u2,&u,sizeof(u));
                        u2.dist = u.dist + amount;
                        u2.v[i] -= amount;
                        u2.v[j] += amount;
                        // 判断此状态是否已访问
                        if(!vis[u2.v[0]][u2.v[1]]) {
                                q.push(u2);
                                vis[u2.v[0]][u2.v[1]] = 1;
                        }
                }
        }
        while(d >= 0) {
                if(ans[d] >= 0) {
                        printf("%d %d\n",ans[d],d);
                        return;
                }
                d--;
        }
}
int main() {
        int T;
        while(~scanf("%d",&T) && T) {
                while(T--) {
                        int a,b,c,d;
                        scanf("%d%d%d%d",&a,&b,&c,&d);
                        solve(a,b,c,d);
                }
        }
        return 0;
}
</span></strong>


UVA 10603 Fill(状态空间搜索,倒水问题)

【题目链接】uva-10603 【题意】设3个杯子的容量分别为a, b, c,最初只有第3个杯子装 满了c升水,其他两个杯子为空。最少需要倒多少升水才能让某一个杯子中的水有d升呢?如果无法做到恰好d升...

Fill (Uva 10603 bfs 倒水问题)

题意:三个杯子容量分别为a,b,c,现在c是满的,a和b是空的,两个杯子 i 向 j 倒水,要么 i 倒完了 j 还没满,要么 j 满了 i 还有剩余,问达到某个杯子水量为d时总共倒得最小水量是多少?...

例题7-8 UVA 10603 Fill 倒水问题

完全仿照紫书上来写的! 书中大体思路是: 用ans[]来记录答案,不断取最小值来更新! 用vis[][]来表示是否访问过,之所以是二维数组,是因为总水量是固定的,两个杯子确定,第三个杯子自然也就确定,...

UVa 10603 - Fill,经典倒水问题+隐式图搜索+dfs

题目链接: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=110&page=show_p...

uva 10603(Fill, 隐式图搜索问题)

题目大意: 有三个杯子的容量分别为a, b, c,  最初只有第3个杯子装满了c升水,其他两个杯子为空。最少需要倒多少升水才能让某个水杯有d升,如果无法达到d升,找到某个杯子的水是d’升,其中d‘ ...

uva10603 倒水问题

状态搜索、uva

UVA10603 倒水问题

紫书刷到第7章了,感觉也有点难度了,写了一道BFS的变形的题目,写了两个小时,题目其实不难,只是,自己总是犯各种小错误。 题目略:大体意思是有三个杯子(已知道三个杯子的容量ABC),每个杯子开始的...

UVA10603倒水问题加优先队列

这题是一个倒水问题的变形,也是隐式图的搜索,刚开始读错题了,这题让求得是倒水量,而不是倒水的次数。 然后这题要用优先队列,一旦搜到d,就退出搜索,因为是每次搜索得到新的状态都按照d进行了排序,所以一...

UVa - 10603 - Fill

BFS即可,不过需要注意要求不是步数最少,而是需要水量最少。所以拓展的时候需要取出水量最少的结点进行拓展。用优先队列即可。 #include #include #include #includ...

Uva10603——Fill

求的是倒水量最小,不是次数。 代码: #include #include #include #include using namespace std; struct Node {...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:倒水问题(Fill,UVa 10603)
举报原因:
原因补充:

(最多只允许输入30个字)