zoukankan      html  css  js  c++  java
  • P1433 吃奶酪(状压dp)

    状压dp

    状压(dp)可以解决(n<=21)的情况。

    在状压时(dp[i][j]),代表在第(i)个位置时且走过二进制状态(j)的最佳答案。

    将状态压成二进制的形式去求解。

    例:10100110代表经历了2、3、6、8四种状态。

    时间复杂度(O(n^2 2^n))

    题目描述

    房间里放着 n*n块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0)(0,0) 点处。

    输入格式

    第一行有一个整数,表示奶酪的数量 n。

    第 2 到第 (n + 1)行,每行两个实数,第 (i + 1) 行的实数分别表示第 i 块奶酪的横纵坐标 (x_i, y_i)

    输出格式

    输出一行一个实数,表示要跑的最少距离,保留 2 位小数。

    思路

    先将每条边的距离都预处理。

    还需要预处理第i个奶酪到第i个奶酪的距离。这里直接将((0,0))的位置也加了进去,也就是用来初始化了。

    for(int i = 1; i <= n; ++i) {
    	dp[i][1 << (i - 1)] = f[0][i];
    }
    

    接下来三层循环。

    分别枚举二进制的状态、当前点所在的位置和能在当前状态下转移到当前点的位置。

    第二层循环需要判断一下(i)在当前二进制状态下是否已走过,如果根本没走过则不需要进行接下来的计算。

    第三层循环判断当前点是否已走过,且当前点不和(i)相同。

    转移方程:

    [dp[i][k]=min(dp[i][k],dp[j][k-(1<<(i-1))]+f[i][j]) ]

    (k)表示此时的二进制状态(指已经走过哪些点),起点为(j),终点为(i)

    (dp[j][k-(1<<(i-1))])表示在(j)点走过没有(i)的状态的距离

    最大需要的单独二进制状态为((1<<(n-1))),但是所有的二进制状态和为((1<<n)-1)

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define DOF 0x7f7f7f7f
    #define endl '
    '
    #define mem(a, b) memset(a, b, sizeof(a))
    #define debug(case, x) cout << case << "  : " << x << endl
    #define open freopen("ii.txt", "r", stdin)
    #define close freopen("oo.txt", "w", stdout)
    #define IO                       
        ios::sync_with_stdio(false); 
        cin.tie(0);                  
        cout.tie(0)
    #define pb push_back
    using namespace std;
    //#define int long long
    #define lson rt << 1
    #define rson rt << 1 | 1
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef pair<long long, long long> PII;
    const int maxn = 1e6 + 10;
    
    double f[20][20];
    double x[20], y[20];
    double dp[18][(1 << 15) + 5];
    
    double dis(int i, int j) {
        return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
    }
    
    int main() {
        double ans = 1e18;
        for(int i = 1; i <= 15; ++i) {
            for(int j = 1; j <= ((1 << 15) + 8); ++j) {
                dp[i][j] = 1e18;
            }
        }
    
        int n;
        scanf("%d", &n);
        x[0] = y[0] = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%lf%lf", &x[i], &y[i]);
        }
    
        for(int i = 0; i < n; ++i) {
            for(int j = i + 1; j <= n; ++j) {
                f[i][j] = f[j][i] = dis(i, j);
            }
        }
    
        for(int i = 1; i <= n; ++i) {
            dp[i][1 << (i - 1)] = f[0][i];
        }
        for(int k = 1; k < (1 << n); ++k) {
            for(int i = 1; i <= n; ++i) {
                if((k & (1 << (i - 1))) == 0) continue;
                for(int j = 1; j <= n; ++j) {
                    if(i == j) continue;
                    if((k & (1 << (j - 1))) == 0) continue;
                    dp[i][k] = min(dp[i][k], dp[j][k - (1 << (i - 1))] + f[i][j]);
                }
            }
        }
        for(int i=1;i<=n;++i){
            ans=min(ans,dp[i][(1<<n)-1]);
        }
        printf("%.2f
    ",ans);
    
    }
    
    
  • 相关阅读:
    第四周助教小结
    java课程总结
    第十四周总结
    第十三周实验报告
    第十二周课程报告
    第十一周课程总结
    第十周课程总结
    第九周课程总结&实验报告(七)
    第八周课程总结&实验报告(六)
    第七周课程总结&实验报告(五)
  • 原文地址:https://www.cnblogs.com/waryan/p/13452916.html
Copyright © 2011-2022 走看看