• bzoj 4006: [JLOI2015]管道连接


    4006: [JLOI2015]管道连接

    Time Limit: 30 Sec  Memory Limit: 128 MB
    Submit: 1062  Solved: 576
    [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。
     
    /*
        斯坦纳森林
        每一棵斯坦纳树都是一个斯坦纳树裸题啊
            分两步dp:
            1.枚举子集
            2.spfa 
        最后合并就好了。 
    */
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define maxn 1050
    using namespace std;
    int n,m,p,oo;
    int g[maxn],f[maxn][maxn],c[maxn],d[maxn],bin[maxn],num,head[maxn];
    bool vis[maxn];
    queue<int>q;
    struct node{int to,pre,v;}e[20010];
    void Insert(int from,int to,int v){
        e[++num].to=to;
        e[num].pre=head[from];
        e[num].v=v;
        head[from]=num;
    }
    void spfa(int S){
        while(!q.empty()){
            int now=q.front();q.pop();vis[now]=0;
            for(int i=head[now];i;i=e[i].pre){
                int to=e[i].to;
                if(f[to][S]>f[now][S]+e[i].v){
                    f[to][S]=f[now][S]+e[i].v;
                    if(!vis[to])q.push(to),vis[to]=1;
                } 
            }
        } 
    }
    bool check(int S){
        int now;
        for(int i=1;i<=p;i++){
            now=S&bin[i];
            if(!now||now==bin[i])continue;
            return 0;
        }
        return 1;
    } 
    int qread(){
        int i=0,j=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')j=-1;ch=getchar();}
        while(ch<='9'&&ch>='0')i=i*10+ch-'0',ch=getchar();
        return i*j;
    }
    int main(){
        n=qread();m=qread();p=qread();
        int x,y,z;
        for(int i=1;i<=m;i++){
            x=qread();y=qread();z=qread();
            Insert(x,y,z);Insert(y,x,z);
        }
        for(int i=1;i<=p;i++)c[i]=qread(),d[i]=qread();
        for(int i=1;i<=p;i++)
            for(int j=1;j<=p;j++)
                if(c[i]==c[j])bin[i]|=(1<<(j-1));
        memset(f,0x3f,sizeof(f));
        memset(g,0x3f,sizeof(g));
        for(int i=1;i<=p;i++)f[d[i]][1<<i-1]=0;oo=g[0];
        for(int S=1;S<(1<<p);S++){
            for(int i=1;i<=n;i++){
                for(int sta=S;sta;sta=(sta-1)&S)
                    f[i][S]=min(f[i][S],f[i][sta]+f[i][S^sta]);
                if(f[i][S]<oo)q.push(i),vis[i]=1;
            }
            spfa(S);
            if(!check(S))continue;
            for(int i=1;i<=n;i++)g[S]=min(g[S],f[i][S]);
            for(int i=S;i;i=(i-1)&S)g[S]=min(g[S],g[i]+g[S^i]);
        }
        printf("%d",g[(1<<p)-1]); 
    }
  • 相关阅读:
    Anaconda+Tensorflow环境安装与配置
    计算机视觉(视频追踪检测分类、监控追踪)常用测试数据集
    迁移学习( Transfer Learning )
    matlab函数_连通区域
    GMM的EM算法实现
    对​O​p​e​n​C​V​直​方​图​的​数​据​结​构​C​v​H​i​s​t​o​g​r​a​m​的​理​解
    opencv基于混合高斯模型的图像分割
    LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    视频测试序列(转)
    高职扩招,拿大专学历
  • 原文地址:https://www.cnblogs.com/thmyl/p/8312921.html
Copyright © 2020-2023  润新知