• 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;
    }
    
  • 相关阅读:
    MYSQL中replace into的用法
    Typora自定义样式
    Advanced Installer轻松带你入门
    H2数据库入门,看这篇就对了
    Linux之vim的使用
    Linux文件上传与下载
    @ConfigurationProperties 注解使用姿势,这一篇就够了
    Javadoc 使用详解
    MySQL学习提升
    JS前端获取用户的ip地址的方法
  • 原文地址:https://www.cnblogs.com/lrj998244353/p/8847768.html
Copyright © 2020-2023  润新知