bzoj4006: [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)这四对情报站连接。
数据范围与提示
对于 100% 的数据,0<ci≤p≤10, 0<ui,vi,di≤n≤1000, 0≤m≤3000, 0≤wi≤200000。
其中有20%的数据,p=2;
另有20%的数据,p=4。
题解
和bzoj4774差不多,只不过给定的点集大小不固定,把判断状态是否合法的函数改一下就行了。
代码
#include<bits/stdc++.h>
#define MAXN 3010
#define INF 0x3f3f3f3f
namespace IO{
char buf[1<<15],*fs,*ft;
inline char gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline int qr(){
int x=0,rev=0,ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=gc();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
return rev?-x:x;}
}using namespace IO;
using namespace std;
struct Edge{int t,next,v;}e[MAXN<<1];
int N,M,P,head[MAXN],cnt,f[MAXN][1<<10],c[12],g[1<<10],num[12],tmp[12];
bool vis[MAXN];
queue<int>q;
inline void Add_Edge(int from,int to,int v){
e[++cnt].t=to;e[cnt].next=head[from];head[from]=cnt;e[cnt].v=v;
e[++cnt].t=from;e[cnt].next=head[to];head[to]=cnt;e[cnt].v=v;
}
inline void Spfa(int S){
for(int i=1;i<=N;i++)if(f[i][S]!=INF){
q.push(i);vis[i]=1;
}
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].t;
if(f[u][S]+e[i].v<f[v][S]){
f[v][S]=f[u][S]+e[i].v;
if(!vis[v])q.push(v),vis[v]=1;
}
}
}
}
inline bool Check(int S){
memset(tmp,0,sizeof(tmp));
for(int i=0;i<P;i++){
if((S>>i)&1){
tmp[c[i+1]]++;
}
}
for(int i=1;i<=P;i++){
if(tmp[i]&&tmp[i]!=num[i])return 0;
}
return 1;
}
int x,y,z;
int main(){
#ifndef ONLINE_JUDGE
freopen("channel.in","r",stdin);
freopen("channel.out","w",stdout);
#endif
N=qr();M=qr();P=qr();
for(int i=1;i<=M;i++){
x=qr();y=qr();z=qr();
Add_Edge(x,y,z);
}
memset(f,INF,sizeof(f));
memset(g,INF,sizeof(g));
for(int i=1;i<=P;i++){
c[i]=qr();x=qr();
num[c[i]]++;
f[x][1<<(i-1)]=0;
}
for(int j=0,ed=(1<<P);j<ed;j++){
for(int i=1;i<=N;i++){
for(int k=j&(j-1);k;k=(k-1)&j){
f[i][j]=min(f[i][j],f[i][k]+f[i][j-k]);
}
}
Spfa(j);
for(int i=1;i<=N;i++)g[j]=min(g[j],f[i][j]);
}
for(int j=0,ed=(1<<P);j<ed;j++){
for(int k=j&(j-1);k;k=(k-1)&j){
if(Check(k)&&Check(j-k)){
g[j]=min(g[j],g[k]+g[j-k]);
}
}
}
printf("%d",g[(1<<P)-1]);
return 0;
}