zoukankan      html  css  js  c++  java
  • 洛谷 P1433 DP 状态压缩

    题目描述

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

    输入输出格式

    输入格式:

    第一行一个数n (n<=15)

    接下来每行2个实数,表示第i块奶酪的坐标。

    两点之间的距离公式=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))

    输出格式:

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

    输入输出样例

    输入样例#1:
    4
    1 1
    1 -1
    -1 1
    -1 -1
    输出样例#1:
    7.41

    这题开始用搜索做的,稍微剪下枝就能水过去,不过时间用的比较多,后来用 DP 做了一遍。

    用二进制表示一个集合,比如  1011 表示一个包含了 0,1,3 结点的集合。

    dp[i][j] 表示,在 i 集合中,以 j 结点作为起始点走完集合中所有点的最短路径。

    dp[i][j] = min(dp[k][x] + len[j][x])

    k 是去掉 j 结点的集合,x 是 k 中的任意一点, len[j][x] 表示 j 到 x 的距离。

    代码:

    #include <iostream>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    const int MAX = 17;
    const int INF = 0x3fffffff;
    
    double dp[1<<MAX][MAX];        // i 集合,以 j 为起始点,最短的路径 
    double r[MAX], c[MAX], len[MAX][MAX];
    int n;
    
    int main(){
    //    freopen("input.txt", "r", stdin);
        
        scanf("%d", &n);
        r[0] = c[0] = 0;
        for(int i=1; i<=n; i++){
            scanf("%lf%lf", &r[i], &c[i]);
        }
        
        //求出两点之间的长度
        for(int i=0; i<=n; i++){
            for(int j=0; j<=n; j++){
                double x1 = r[i], y1 = c[i];
                double x2 = r[j], y2 = c[j];
                len[i][j] = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
            }
        }
        
        double ans = 999999999;
        //DP
        //初始化 
        for(int i=0; i<(1<<MAX); i++)
            for(int j=0; j<MAX; j++)
                dp[i][j] = 999999999;
        for(int i=0; i<=n; i++)        //只有一个结点时,最短路径为 0 
            dp[(1<<i)][i] = 0; 
        
        for(int i=1; i<=((1<<(n+1))-1); i++){        //枚举集合 i 
            for(int j=0; j<=n; j++){
                int t = (1<<j);
                if((t & i) > 0){            //如果 i 结合有第 j 个结点 
                    int k = i - t;            //k 集合等于 i 集合去掉 j 结点
    //                if(i == 3){
    //                    cout << k << endl;
    //                }
                    for(int x=0; x<=n; x++){
                        t = (1<<x);
                        if((t & k) > 0){    //如果 k 集合里有第 x 个结点 
                            //dp[k][x] + len[x][j] : 从 j 点出发到 x 点的距离再加上从 x 出发走完 k 集合的最短距离 
                            dp[i][j] = min(dp[i][j], dp[k][x] + len[j][x]);
                        }
                    } 
                }
            }
        }
        
        ans = dp[((1<<(n+1))-1)][0];
        printf("%.2lf", ans);
        
        return 0;
    }
  • 相关阅读:
    FBWF和EWF的对比
    还原数据库备份文件时,关于“System.Data.SqlClient.SqlError:媒体集有2个媒体簇,但只提供了1个。必须提供所有成员”的处理方式
    C#基础(八)——C#数据类型的转换
    C#基础(七)——静态类与非静态类、静态成员的区别
    C#基础(六)——值类型与引用类型
    C#基础(五)——类中私有构造函数作用
    C#基础(四)——ref与out的区别
    C#基础(三)—重载与覆盖
    oracle exists和 not exists 的用法
    easyUI 常见问题点
  • 原文地址:https://www.cnblogs.com/lighter-blog/p/7352682.html
Copyright © 2011-2022 走看看