bzoj 4006: [JLOI2015]管道连接
4006: [JLOI2015]管道连接
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 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
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]); }