现在的位置: 首页 > 综合 > 正文

UVa #10603 Fill (例题7-8)

2018年10月14日 ⁄ 综合 ⁄ 共 1607字 ⁄ 字号 评论关闭

看了书上的解法,自己写了一遍,几乎没遇到什么障碍。不过看Board上面的讨论,觉得细节上需要注意的地方还是挺多的。。纯粹自己写肯定分分钟跪下

1、vis数组只用开两维

看到讨论中大家都是用的三维数组vis[201][201][201],其实有了两杯水的数据,第三杯水可以用总量减去两杯水的量得到,所以不需要维护3维数组

2、解的存储

因为题目说如果取不到d,就要打印出比d小的最大的可能解d'以及倒水的量,所以bfs就把所有可能的d以及倒水量都存了下来,如果之前取到过这个d,则判断倒水量是否比之前的少,如果满足要求的话就更新数据。最后从d开始往下减小,遇到第一个取到过的解就打印并返回

3、优先队列

首先要注意这道题问的是倒水量最少,而不是倒水次数最少,而这两者没有必然关系。所以在bfs的时候,就不能用普通queue存储需要遍历的节点,而应该用一个优先队列,让倒水量少的排在前头。

另外在讨论中看到很多人用的是dfs,并且很多人得了TLE。然后大家比较推荐的解法是dijkstra。

Run Time: 0.142s

#define UVa  "LT7-8.10603.cpp"

#include<cstring>
#include<cstdlib>
#include<cstdio>

#include<queue>

#define maxn 500

using namespace std;

struct Node {
    int v[3], dist;
    bool operator < (const Node& n) const {
        return dist > n.dist;
    }
};

//Global Variables.
int vis[maxn][maxn];
int ans[maxn];
/////


void update_ans(Node& u) {
    for(int i = 0; i < 3; i ++) {
        int d = u.v[i];
        if(ans[d] < 0 || u.dist < ans[d])  ans[d] = u.dist;
    }
}

void solve(int a, int b, int c, int d) {
    int cap[3] = {a,b,c};
    memset(vis, 0, sizeof(vis));
    memset(ans, -1, sizeof(ans));

    Node startN;
    startN.v[0] = startN.v[1] = 0;
    startN.v[2] = c;
    startN.dist = 0;
    priority_queue<Node> q;
    q.push(startN);
    vis[0][0] = 1;
    while(!q.empty()) {
        Node u = q.top(); q.pop();
        update_ans(u);
        for(int i = 0; i < 3; i ++) {
            for(int j = 0; j < 3; j ++) if(i != j) {
                if(u.v[j] == cap[j] || u.v[i] == 0) continue;           //Empty / Full
                int amount = min(cap[j] - u.v[j], u.v[i]);              //Amount of water to fill
                Node newN;
                memcpy(&newN, &u, sizeof(u));
                newN.v[i] = u.v[i] - amount;
                newN.v[j] = u.v[j] + amount;
                newN.dist = u.dist + amount;
                if(!vis[newN.v[0]][newN.v[1]]) {
                    q.push(newN);
                    vis[newN.v[0]][newN.v[1]] = 1;
                }
            }
        }
    }

    while(d>=0) {          //print ans
        if(ans[d] >= 0) {
            printf("%d %d\n", ans[d], d);
            return;
        }
        d--;
    }
}

int main() {
    int kase;
    scanf("%d", &kase);
    while(kase--) {
        int a, b, c, d;
        scanf("%d%d%d%d", &a, &b, &c, &d);
        solve(a, b, c, d);
    }
    return 0;
}



抱歉!评论已关闭.