zoukankan      html  css  js  c++  java
  • BZOJ4006 JLOI2015 管道连接(斯坦纳树生成森林)

    4006: [JLOI2015]管道连接
    
    Time Limit: 30 Sec  Memory Limit: 128 MB
    
    Description
    小铭铭最近进入了某情报部门,该部门正在被如何建立安全的通道连接困扰。
    该部门有 n 个情报站,用 1 到 n 的整数编号。给出 m 对情报站 ui;vi 和费用 wi,表示情
    报站 ui 和 vi 之间可以花费 wi 单位资源建立通道。
    如果一个情报站经过若干个建立好的通道可以到达另外一个情报站,那么这两个情报站就
    建立了通道连接。形式化地,若 ui 和 vi 建立了通道,那么它们建立了通道连接;若 ui 和 vi 均
    与 ti 建立了通道连接,那么 ui 和 vi 也建立了通道连接。
    现在在所有的情报站中,有 p 个重要情报站,其中每个情报站有一个特定的频道。小铭铭
    面临的问题是,需要花费最少的资源,使得任意相同频道的情报站之间都建立通道连接。
    
    Input
    第一行包含三个整数 n;m;p,表示情报站的数量,可以建立的通道数量和重要情报站的数
    量。接下来 m 行,每行包含三个整数 ui;vi;wi,表示可以建立的通道。最后有 p 行,每行包含
    两个整数 ci;di,表示重要情报站的频道和情报站的编号。
    
    Output
    输出一行一个整数,表示任意相同频道的情报站之间都建立通道连接所花费的最少资源总量。
    
    Sample Input
    5 8 4
    1 2 3
    1 3 2 
    1 5 1
    2 4 2
    2 5 1
    3 4 3 
    3 5 1
    4 5 1
    1 1
    1 2
    2 3
    2 4
    
    Sample Output
    4
    
    HINT
    选择 (1; 5); (3; 5); (2; 5); (4; 5) 这 4 对情报站连接。
    对于 100% 的数据,0 <ci <= p <= 10; 0 <ui;vi;di <= n <= 1000; 0 <= m <= 3000; 0 <= wi <=20000。
    

    算法讨论:

    斯坦纳树生成森林。题解再补。

    代码:

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
     
    using namespace std;
    const int N = 1000 + 5;
    const int inf = 0xf0f0f0f;
     
    int n, m, p, cnt, channel, tot_channel;
    int g[1025], f[N][1025], head[N], inque[N];
    queue <int> q;
     
    struct Edge {
        int from, to, dis, next;
    }edges[6005];
     
    struct Data {
        int c, num;
        bool operator < (const Data &STD) const {
            return c < STD.c;
        }
    }key[11];
     
    void insert(int from, int to, int dis) {
        ++ cnt;
        edges[cnt].from = from; edges[cnt].to = to; edges[cnt].dis = dis;
        edges[cnt].next = head[from]; head[from] = cnt;
    }
     
    void spfa(int State) {
        while(!q.empty()) {
            int x = q.front(); q.pop();
            inque[x] = 0;
            for(int i = head[x]; i; i = edges[i].next) {
                int v = edges[i].to;
                if(f[v][State] > f[x][State] + edges[i].dis) {
                    f[v][State] = f[x][State] + edges[i].dis;
                    if(!inque[v]) {
                        inque[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
    }
     
    int solve() {
        int U = 1 << channel;
        for(int State = 0; State < U; ++ State) {
            for(int i = 1; i <= n; ++ i) {
                for(int s = (State - 1) & State; s; s = (s - 1) & State)
                    f[i][State] = min(f[i][State], f[i][s] + f[i][State - s]);
                if(f[i][State] != inf) q.push(i), inque[i] = 1;
            }
            spfa(State);
        }
        int ans = inf;
        for(int i = 1; i <= n; ++ i) ans = min(ans, f[i][U - 1]);
        return ans;
    }
     
    #define stone_
    int main() {
    #ifndef stone_
        freopen("channel.in", "r", stdin);
        freopen("channel.out", "w", stdout);
    #endif
     
        int u, v, w;
        scanf("%d%d%d", &n, &m, &p);
        for(int i = 1; i <= m; ++ i) {
            scanf("%d%d%d", &u, &v, &w);
            insert(u, v, w); insert(v, u, w);
        }
        for(int i = 1; i <= p; ++ i)
          scanf("%d%d", &key[i].c, &key[i].num);
        sort(key + 1, key + p + 1);
        for(int i = 1; i <= p; ++ i) {
          if(key[i].c != key[i - 1].c) ++ tot_channel;
            key[i].c = tot_channel;
        }
        int U = 1 << tot_channel;
        memset(g, 0xf, sizeof g);
        for(int State = 0; State < U; ++ State) {
            memset(f, 0xf, sizeof f);
            channel = 0;
            for(int i = 1; i <= p; ++ i)
              if(State & 1 << (key[i].c - 1)) {
                    f[key[i].num][1 << channel] = 0;
                    channel ++;
              }
            g[State] = solve();
        }
        for(int State = 0; State < U; ++ State) {
            for(int s = (State - 1) & State; s; s = (s - 1) & State)
              g[State] = min(g[State], g[s] + g[State - s]);
        }
        printf("%d
    ", g[U - 1]);
     
    #ifndef stone_
        fclose(stdin); fclose(stdout);
    #endif
        return 0;
    }
    
  • 相关阅读:
    make menuconfig显示错误“Your display is too small to run Menuconfig!”
    程序员的那点事(转自java老师李明志)
    不必太羡慕别人
    把数据存储到 XML 文件
    关于session
    网页中的服务器端和客户端脚本
    没有一种成功是不经历磨砺的
    考试导数据总结(一)
    我们应该爱上“犯错”——读应试教育的死穴,恰在于堵死了孩子“犯错”的空间
    软考——多媒体
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5407499.html
Copyright © 2011-2022 走看看