zoukankan      html  css  js  c++  java
  • 【hdu3311】Dig The Wells(斯坦纳树+dp)

    传送门

    题意:
    给出(n)个重要点,还有其余(m)个点,(p)条边。
    现在要在这(n+m)个点中挖几口水井,每个地方的费用为(w_i)。连接边也有费用。
    问使得这(n)个地点都有水井(或直接、间接与水井相连)的最小代价。

    思路:
    有点巧妙。。建立一个虚点连向所有点,边权为(w_i)。然后直接求以(0)为根的斯坦纳树即可,最后再子集(dp)一下就行。

    原理就是,此时这(n)个点连通,并且以(0)为根,脑补一下即可发现:要么直接与(0)相连,要么间接相连,直接相连就是这里挖井,间接相连的话就是通过其它地方引水。

    代码如下:

    /*
     * Author:  heyuhhh
     * Created Time:  2019/11/27 14:23:05
     */
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <iomanip>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1010, M = 10005, P = 6;
    
    int n, m, p;
    
    struct Edge {
        int v, w, next;   
    }e[M << 1];
    int head[N], tot;
    void adde(int u, int v, int w) {
        e[tot].v = v; e[tot].w = w; e[tot].next = head[u]; head[u] = tot++;   
    }
    int dp[N][1 << P];
    queue <int> q;
    bool in[N];
    void spfa(int s) {
        while(!q.empty()) {
            int u = q.front(); q.pop(); in[u] = 0;
            for(int i = head[u]; i != -1; i = e[i].next) {
                int v = e[i].v;
                if(dp[v][s] > dp[u][s] + e[i].w) {
                    dp[v][s] = dp[u][s] + e[i].w;
                    if(!in[v]) q.push(v), in[v] = 1;   
                }
            }
        }
    }
    int g[1 << P];
    
    void run(){
        memset(head, -1, sizeof(head)); tot = 0;
        for(int i = 1; i <= n + m; i++) {
            int w; cin >> w;
            adde(0, i, w);
            adde(i, 0, w);
        }
        for(int i = 1; i <= p; i++) {
            int u, v, w; cin >> u >> v >> w;
            adde(u, v, w); adde(v, u, w);
        }
        memset(dp, INF, sizeof(dp));
        memset(g, INF, sizeof(g));
        for(int i = 1; i <= n; i++) {
            dp[i][1 << (i - 1)] = 0;
        }
        int lim = (1 << n);
        for(int S = 1; S < lim; S++) {
            for(int i = 0; i <= n + m; i++) {
                for(int s = (S - 1) & S; s; s = (s - 1) & S) {
                    dp[i][S] = min(dp[i][S], dp[i][s] + dp[i][S - s]);
                }
                if(dp[i][S] < INF) q.push(i), in[i] = 1;
            }
            spfa(S);
            g[S] = dp[0][S];
        }
        for(int S = 1; S < lim; S++) {
            for(int s = (S - 1) & S; s; s = (s - 1) & S) {
                g[S] = min(g[S], g[s] + g[S - s]);   
            }
        }
        cout << g[lim - 1] << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m >> p) run();
        return 0;
    }
    
  • 相关阅读:
    Visio 2003 怎样将用例图画的更美观些
    Mvc项目实例 MvcMusicStore 四
    Mvc项目实例 MvcMusicStore 三
    Lock 会引起死锁吗
    进程和线程
    vb.net winform pos机并口打印机打印以及开钱箱。。。。
    .net winfrom 定义全局快捷键!
    WebBrowser中HTML的js与winform中其他的窗体调用。。。
    [转]确认网络环境3G/WIFI
    图片分割的代码
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11954445.html
Copyright © 2011-2022 走看看