zoukankan      html  css  js  c++  java
  • BZOJ4006: [JLOI2015]管道连接(斯坦纳树,状压DP)

    Time Limit: 30 Sec  Memory Limit: 128 MB
    Submit: 1171  Solved: 639
    [Submit][Status][Discuss]

    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。

     

    Source

    斯坦纳森林

    设$f[i][sta]$表示$i$号节点,与关键节点的联通性为$sta$时的最小值

    假设我们已经求出了$f$

    那么我们令$g[sta]$表示,颜色联通性为$sta$时的最小值

    $g$比较好求,枚举子集转移就可以

    $f$的话,如果学过斯坦纳树也比较好求

    按照套路,两种转移方法,一种是枚举子集,一种是SPFA

    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int MAXN = 1e6 + 10;
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
        return x * f;
    }
    int N, M, P;
    struct node {
        int u, v, w, nxt;
    }E[MAXN];
    int head[MAXN], num = 1;
    inline void AddEdge(int x, int y,int z) {
        E[num].u = x; E[num].v = y; E[num].w = z;
        E[num].nxt = head[x]; head[x] = num++;
    }
    struct Point {
        int color, ID;
    }a[MAXN];
    int f[1051][1051], g[1051];
    int vis[MAXN], sum[MAXN];
    queue<int>q;
    void SPFA(int now) {
        while(q.size() != 0) {
            int p = q.front(); q.pop(); vis[p] = 0;
            for(int i = head[p]; i != -1; i = E[i].nxt) {
                int v = E[i].v;
                if(f[v][now] > f[p][now] + E[i].w) {
                    f[v][now] = f[p][now] + E[i].w;
                    if(!vis[v]) vis[v] = 1, q.push(v);
                }
            }
        }
    }
    int tmp[11];
    bool check(int sta) {
        memset(tmp, 0, sizeof(tmp));
        for(int i = 1; i <= 10; i++)
            if(sta & (1 << i - 1)) tmp[a[i].color]++;
        for(int i = 1; i <= 10; i++)
            if(tmp[i] && tmp[i] != sum[i]) return 0;
        return 1;
    }
    int main() {
        #ifdef WIN32
        freopen("a.in", "r", stdin);
        #endif
        memset(head, -1, sizeof(head));
        N = read(), M = read(), P = read();
        for(int i = 1; i <= M; i++) {
            int x = read(), y = read(), z = read();
            AddEdge(x, y, z);AddEdge(y, x, z);
        }
        memset(f, 0x3f, sizeof(f));
        memset(g, 0x3f, sizeof(g));
        for(int i = 1; i <= P; i++) 
            a[i].color = read(), a[i].ID = read(), sum[a[i].color]++,f[a[i].ID][1 << (i - 1)] = 0;        
        int limit = (1 << P) - 1;    
        for(int sta = 0; sta <= limit; sta++) {
            for(int i = 1; i <= N; i++) {
                for(int S = sta; S; S = (S - 1) & sta) 
                    f[i][sta] = min(f[i][sta], f[i][S] + f[i][sta - S]);
                q.push(i),vis[i] = 1;
            }
            SPFA(sta);    
        }
        for(int sta = 0; sta <= limit; sta++) 
            for(int i = 1; i <= N; i++)
                g[sta] = min(g[sta], f[i][sta]);
        for(int sta = 0; sta <= limit; sta++)
            if(check(sta))
                for(int S = sta; S; S = (S - 1) & sta)
                    if(check(S))
                        g[sta] = min(g[sta], g[S] + g[sta - S]);
        printf("%d", g[(1 << P) - 1]);
        return 0;
    }
  • 相关阅读:
    我与计算机简述
    第十五周计应151班第四组排球计分程序
    第十五周排球积分查询程序
    本周总结
    计应1班第4小组第一次产品计划会议
    本周总结
    计应1班第4小组“排球比赛计分程序”的典型用户、创立场景、用户故事
    排球计分规则功能说明书
    我与计算机
    5th 各组作品alpha发布体会
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8977219.html
Copyright © 2011-2022 走看看