zoukankan      html  css  js  c++  java
  • [JLOI2015]管道连接

    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

    首先求出(f_{sta})表示包含频率集合(sta)的最小斯坦纳生成森林的值,于是我们有

    [f_{sta}=min{f_s+f_{sta-s}|ssubset sta} ]

    然后,就瞎jb乱搞吧

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x>=10)     print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e3,M=3e3,K=10;
    int pre[(M<<1)+10],now[N+10],child[(M<<1)+10],val[(M<<1)+10],tot;
    int f[N+10][(1<<K)+10],h[N+10],Ans[(1<<K)+10],sum[K+10],tmp[K+10];
    bool vis[N+10];
    struct S1{
    	int col,ID;
    	void join(){col=read(),ID=read();}
    }imp[K+10];//important
    int n,m,k;
    void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    bool check(int sta){
    	memset(tmp,0,sizeof(tmp));
    	for (int i=1;i<=k;i++)	if ((1<<(i-1))&sta)	tmp[imp[i].col]++;
    	for (int i=1;i<=K;i++)	if (tmp[i]&&tmp[i]!=sum[i])	return 0;
    	return 1;
    }
    void spfa(int sta){
    	int head=0,tail=0;
    	for (int i=1;i<=n;i++)	h[++tail]=i,vis[i]=1;
    	while (head!=tail){
    		if (++head>N)	head=1;
    		int Now=h[head];
    		for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){
    			if (f[son][sta]>f[Now][sta]+val[p]){
    				f[son][sta]=f[Now][sta]+val[p];
    				if (!vis[son]){
    					if (++tail>N)	tail=1;
    					vis[h[tail]=son]=1;
    				}
    			}
    		}
    		vis[Now]=0;
    	}
    }
    int main(){
    	n=read(),m=read(),k=read();
    	for (int i=1;i<=m;i++){
    		int x=read(),y=read(),z=read();
    		join(x,y,z),join(y,x,z);
    	}
    	memset(f,63,sizeof(f));
    	memset(Ans,63,sizeof(Ans));
    	for (int i=1;i<=k;i++)	imp[i].join(),sum[imp[i].col]++;
    	for (int i=1;i<=k;i++)	f[imp[i].ID][1<<(i-1)]=0;
    	for (int sta=0;sta<1<<k;sta++){
    		for (int i=1;i<=n;i++)
    			for (int s=(sta-1)&sta;s;s=(s-1)&sta)
    				f[i][sta]=min(f[i][sta],f[i][s]+f[i][sta^s]);
    		spfa(sta);
    	}
    	for (int sta=0;sta<1<<k;sta++)	for (int i=1;i<=n;i++)	Ans[sta]=min(Ans[sta],f[i][sta]);
    	for (int sta=0;sta<1<<k;sta++){
    		if (!check(sta))	continue;
    		for (int s=(sta-1)&sta;s;s=(s-1)&sta){
    			if (!check(s))	continue;
    			Ans[sta]=min(Ans[sta],Ans[s]+Ans[sta^s]);
    		}
    	}
    	printf("%d
    ",Ans[(1<<k)-1]);
    	return 0;
    }
    
  • 相关阅读:
    java实现简单web服务器(分析+源代码)
    Java中常见的5种WEB服务器介绍
    Android ViewDragHelper完全解析 自定义ViewGroup神器
    设置SVN,Git忽略MAC的.DS_Store文件的方法
    Android中图片大小和屏幕密度的关系讲解
    Android组件化方案及组件消息总线modular-event实战
    机器学习在美团配送系统的实践:用技术还原真实世界
    智能支付稳定性测试实战
    数据库智能运维探索与实践
    【人物志】技术十年:美团第一位前端工程师潘魏增
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9697964.html
Copyright © 2011-2022 走看看