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

    考虑到答案等价于求包含于所有关键集合的斯坦纳森林。
    且强制让关键集合联通。
    那我们只要枚举在森林中的一颗联通树,然后对他跑斯坦纳树即可,最后统计答案。
    数据水的不行。看到题解区一堆代码错也能过的。

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define ll long long
    #define N 11
    #define M 1005
    
    ll n,m,p;
    
    ll f[M][1 << N],g[1 << N];
    
    struct P{int to,next,val;}e[M * 10];
    
    ll head[M],cnt;
    
    inline void add(int x,int y,int v){
    	e[++cnt].to = y;
    	e[cnt].next = head[x];
    	head[x] = cnt;
    	e[cnt].val = v;
    }
    
    std::queue<int>QWQ;
    
    bool vis[M];
    
    inline void spfa(ll ID){
    	for(int i = 1;i <= n;++i)
    	if(f[i][ID] < 1e9)QWQ.push(i),vis[i] = 1;
    	while(!QWQ.empty()){
    		int u = QWQ.front();
    		QWQ.pop();
    		for(int i = head[u];i;i = e[i].next){
    			int v = e[i].to;
    			if(f[v][ID] > f[u][ID] + e[i].val){
    				f[v][ID] = f[u][ID] + e[i].val;
    				if(!vis[v]){
    					vis[v] = 1;
    					QWQ.push(v);
    				}
    			}
    		}
    		vis[u] = 0;
    	}
    }
    
    ll ID[M],num[M],w[1 << N];
    
    int main(){
    	scanf("%lld%lld%lld",&n,&m,&p);
    	for(int i = 1;i <= m;++i){
    		ll x,y,v;
    		scanf("%lld%lld%lld",&x,&y,&v);
    		add(x,y,v);
    		add(y,x,v);
    	}
    	std::memset(ID,-1,sizeof(ID));
    	for(int i = 1;i <= p;++i){
    		ll x,y;
    		scanf("%lld%lld",&x,&y);
    		ID[y] = i - 1;
    		num[x] |= (1 << (i - 1));
    	}
    	std::memset(f,60,sizeof(f));
    	for(int i = 1;i <= n;++i)
    	if(ID[i] == -1)f[i][0] = 0;else f[i][(1 << ID[i])] = 0;
    	for(ll i = 0;i < (1ll << p);++i){
    		if(i){
    			for(int k = 1;k <= n;++k)
    			for(ll j = (i - 1) & i;j;j = (j - 1) & i)
    			f[k][i] = std::min(f[k][i],f[k][j]  + f[k][i ^ j]);
    		}
    		spfa(i);
    	}
    	std::memset(w,60,sizeof(w));
    	for(ll i = 0;i < (1 << p);++i)
    	for(int j = 1;j <= n;++j)
    	w[i] = std::min(w[i],f[j][i]);
    	std::memset(g,60,sizeof(g));
    	g[0] = 0;	
    	for(ll i = 1;i < (1 << p);++i)
    	for(ll j = i;j;j = (j - 1) & i){
    		ll s = 0;
    		for(ll k = 1;k <= p;++k)
    		if(j & num[k]) s |= num[k];
    		g[i] = std::min(g[i],g[i ^ j] + w[s]);
    	}
    	std::cout<<g[(1 << p) - 1]<<std::endl;
    }
    
  • 相关阅读:
    hbase权威指南PDF下载
    流畅的pythonPDF下载
    现代操作系统PDF下载
    Kafka权威指南PDF下载
    java核心技术卷1PDF下载
    计算机网络自顶向下方法PDF下载
    git gitlab 部署
    MySQL 索引、事务与存储引擎(详细解读)
    QT: Layout布局间消除间隙(修改layout内置参数)
    数据结构---归并排序
  • 原文地址:https://www.cnblogs.com/dixiao/p/15201159.html
Copyright © 2011-2022 走看看