• [NOIp2017] 宝藏


    类型:状压

    传送门:>Here<

    题意:给出$N$个点藏有宝藏,有$M$条可以打通的边(都未打通)。你可以选任意一个点作为起点出发,每一次可以打通一条边来挖目的地的宝藏(不能打通已经挖完宝藏的两个点之间的边),其中打通一条边的费用是$L imes K$,其中$L$表示边的长度,$K$表示从当前点到起点打通的路径经过了几个点。问挖完所有宝藏的最小总费用

    解题思路

    由于$N leq 12$,考虑状压。其中二进制状态$S$中为$1$的那一位表示已经挖掘

    可以枚举起点$i$,设立数组$dp[S]$表示以$i$为起点且到达状态$S$所需要的最小费用,因此答案就是$Min{ dp[2^n-1] }$

    然后从起点开始搜索,每一次枚举已经挖掘的所有点(设当前点为$j$,当前状态为$S$),再枚举这一次要打通的点$k$。记录$dis[j]$表示从$j$到起点经过的点的数量,也就是题目中的$K$。则$$dp[S|k] =  Min{dp[S] + dis[j]*cost(j ightarrow k)}$$

    这样的复杂度并不是$N!$,因为$dp$数组是有条件更新的(有点类似记搜)

    Code

    注意需要判断$i$到$j$有边

    /*By DennyQi 2018.8.17*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    const int MAXN = 10010;
    const int MAXM = 27010;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x<<3) + (x<<1) + c - '0', c = getchar();return x * w;
    }
    int N,M,x,y,z,ans;
    int G[15][15],dp[8195],dis[15];
    void DFS(int sta){
        for(int i = 1; i <= N; ++i){
            if(!(sta & (1<<(i-1)))) continue;
            for(int j = 1; j <= N; ++j){
                if(sta & (1<<(j-1))) continue;
                if(G[i][j] == INF) continue;
                if(dis[i] * G[i][j] + dp[sta] < dp[sta | (1<<(j-1))]){
                    dp[sta | (1<<(j-1))] = dis[i] * G[i][j] + dp[sta];
                    dis[j] = dis[i] + 1;
                    DFS(sta | (1<<(j-1)));
                }
            }
        }
    }
    int main(){
        N=r,M=r;
        memset(G, 0x3f, sizeof G);
        ans = INF;
        for(int i = 1; i <= M; ++i){
            x=r,y=r,z=r;
            if(z < G[x][y]){
                G[x][y] = z;
                G[y][x] = z;
            }
        }
        for(int i = 1; i <= N; ++i){
            memset(dp, 0x3f, sizeof dp);
            memset(dis, 0, sizeof dis);
            dis[i] = 1;
            dp[1<<(i-1)] = 0;
            DFS(1<<(i-1));
            ans = Min(ans, dp[(1<<N) - 1]);
        }
        printf("%d", ans);
        return 0;
    }
  • 相关阅读:
    使用PRTG和panabit结合定位网络阻塞的来源
    jQuery实现全选、反选、删除
    ThinkPHP 5接阿里云短信接口
    《存在与时间》读书笔记(三)
    《存在与时间》读书笔记(二)
    自觉原理第十三章自觉情欲之殇
    【原创】自觉原理第十八章红绿灯下的寂静
    自觉原理第十四章欲之殇痛
    追逐文化答案的青春曲上
    自觉与【转载】《大念住经》原经文【中】
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9493636.html
Copyright © 2020-2023  润新知