zoukankan      html  css  js  c++  java
  • uva10857(状态压缩DP)

    uva10857

    题意

    兔子希望在平面上 n 个点上放蛋,每个点最多放一个蛋,初始兔子在 (0, 0) 点,这里有无数个蛋,兔子可以回到这个点取蛋,兔子的速度为 (v * 2^{-i})(i 为携带蛋的数量)。对于每个点 (x, y) ,在 (720+x/2000) 分钟后不能在该点放蛋了。问最多放几个蛋。

    分析

    状态压缩DP。
    dp[i][j][k] 表示到 i 点时,所有点的状态为 j ,身上携带 k 个蛋的最短时间。
    可以使用 BFS 进行记忆化搜索。但是直接这样搜 (O(2^{17}*18^3)) 复杂度太高。

    发现兔子速度的计算公式,(v * 2^{-i}),当 i 很大时,速度会非常小。
    考虑一种特殊情况,只有两个点 A(0, a), B(0, a + b) ,如果每次只携带一个蛋,那么分别在 A B 放 2 个蛋所需时间为 (a * 2 + a + a * 2 + b * 2 = 5a + 2b) ,一次性携带两个蛋所需时间为 (4a + 2b),携带两个蛋更优;
    假如有三个点 A(0, a) B(0, a + b) C(0, a + b + c),一次性携带三个蛋所需时间为 (8a + 4b + 2c),而选择先带一个蛋放到 A,再带两个蛋,所需时间为 (2 * a + a + 4 * a + 4 * b + 2 * c = 7a + 4b + 2c),也就是说分开来带更优,对于更多的点也可以证明。
    所以 k 的最大值为 2,也就是说从初始点最多只能带一个或两个蛋出来。

    code

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 18;
    const double INF = 0x3f3f3f3f;
    const double eps = 1e-9;
    int n;
    double v, dis[MAXN][MAXN];
    double dist(double x1, double y1, double x2, double y2) {
        return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    }
    int x[MAXN], y[MAXN];
    double dp[MAXN][1 << MAXN][3];
    double maxtime[MAXN];
    struct P {
        int pos, state, cnt;
    };
    void bfs() {
        queue<P> q;
        q.push(P{0, 0, 2});
        q.push(P{0, 0, 1});
        dp[0][0][0] = 0;
        dp[0][0][1] = 0;
        dp[0][0][2] = 0;
        while(!q.empty()) {
            P p = q.front(); q.pop();
            for(int i = 1; i <= n; i++) {
                if(!((p.state >> i) & 1)) {
                    P np;
                    np.state = p.state + (1 << i);
                    if(p.cnt) {
                        np.cnt = p.cnt - 1;
                        np.pos = i;
                        double ctime = dis[p.pos][i] / v * (1 << p.cnt);
                        if(dp[p.pos][p.state][p.cnt] + ctime < maxtime[i]) {
                            if(fabs(dp[np.pos][np.state][np.cnt] - INF) < eps) { // eps
                                q.push(P{np.pos, np.state, np.cnt});
                            }
                            dp[np.pos][np.state][np.cnt] = min(dp[np.pos][np.state][np.cnt], dp[p.pos][p.state][p.cnt] + ctime);
                        }
                    } else {
                        double ctime = dis[p.pos][0] / v; // 从当前点回到 0 点
                        double ctime1 = dis[0][i] / v * 2, ctime2 = dis[0][i] / v * 4; // 从 0 点拿 1 个或 2 个到当前点的时间
                        np.pos = i;
                        np.cnt = 0;
                        if(dp[p.pos][p.state][p.cnt] + ctime + ctime1 < maxtime[i]) {
                            if(fabs(dp[np.pos][np.state][np.cnt] - INF) < eps) {
                                q.push(P{np.pos, np.state, np.cnt});
                            }
                            dp[np.pos][np.state][np.cnt] = min(dp[np.pos][np.state][np.cnt], dp[p.pos][p.state][p.cnt] + ctime + ctime1);
                        }
                        np.cnt = 1;
                        if(dp[p.pos][p.state][p.cnt] + ctime + ctime2 < maxtime[i]) {
                            if(fabs(dp[np.pos][np.state][np.cnt] - INF) < eps) {
                                q.push(P{np.pos, np.state, np.cnt});
                            }
                            dp[np.pos][np.state][np.cnt] = min(dp[np.pos][np.state][np.cnt], dp[p.pos][p.state][p.cnt] + ctime + ctime2);
                        }
                    }
                }
            }
        }
    }
    int bits1[1 << MAXN];
    int main() {
        while(cin >> n >> v && (n + v)) {
            x[0] = 0; y[0] = 0;
            for(int i = 0; i <= n; i++) {
                for(int j = 0; j < 3; j++) {
                    for(int k = 0; k < (1 << (1 + n)); k++) {
                        dp[i][k][j] = INF;
                    }
                }
            }
            for(int i = 1; i <= n; i++) {
                cin >> x[i] >> y[i];
            }
            for(int i = 0; i <= n; i++) {
                maxtime[i] = (720 + (1.0 * x[i] / 2000)) * 60;
                for(int j = 0; j <= n; j++) {
                    dis[i][j] = dist(x[i], y[i], x[j], y[j]);
                }
            }
            bfs();
            int ans = 0;
            for(int i = 0; i <= n; i++) {
                for(int k = 0; k < 3; k++) {
                    for(int j = 0; j < (1 << (n + 1)); j++) {
                        bits1[j] = bits1[j >> 1] + (j & 1);
                        if(dp[i][j][k] < INF) {
                            ans = max(ans, bits1[j]);
                        }
                    }
                }
            }
            cout << ans << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    如何提高代码质量
    高效代码审查的十个经验
    代码质量管理(一)
    企业级分布式事务
    X/Open DTP——分布式事务模型
    patchca整合Spring MVC生成超炫的验证码
    兄弟,不要这样写服务器代码
    [转]预备知识—程序的内存分配
    [转]MMORPG服务器架构
    myEclipse使用有感
  • 原文地址:https://www.cnblogs.com/ftae/p/7059128.html
Copyright © 2011-2022 走看看