zoukankan      html  css  js  c++  java
  • bzoj4774: 修路

    Description

    村子间的小路年久失修,为了保障村子之间的往来,法珞决定带领大家修路。对于边带权的无向图 G = (V, E),请选择一些边,使得1 <= i <= d, i号节点和 n - i + 1 号节点可以通过选中的边连通,最小化选中的所有边的权值和。

    Input

    第一行两个整数 n, m,表示图的点数和边数。接下来的 m行,每行三个整数 ui, vi, wi,表示有一条 ui 与 vi 之间,权值为 wi 的无向边。

    1 <= d <= 4

    2d <= n <= 10^4

    0 <= m <= 10^4

    1 <= ui, vi <= n

    1 <= wi <= 1000

    Output

    一行一个整数,表示答案,如果无解输出-1.

    Sample Input

    10 20 1
    6 5 1
    6 9 4
    9 4 2
    9 4 10
    6 1 2
    2 3 6
    7 6 10
    5 7 1
    9 7 2
    5 9 10
    1 6 8
    4 7 4
    5 7 1
    2 6 9
    10 10 6
    8 7 2
    10 9 10
    1 2 4
    10 1 8
    9 9 7
    

    Sample Output

    8
    

    题解

    斯坦纳树模板题。

    设状态(f[i][j])表示:以(i)为根且至少包含了集合(j)中的点的某个连通子树的最小边权和,其中(j)(S)的一个子集。

    (g[j])表示考虑了点集(j)中的点的最优选边方案的边权和,其中(j)(S)的一个子集。

    我们判定(g[j])合法当且仅当要连通的点对同时出现或同时不出现在状态(j)中。

    那么(g[j]=mathrm{min}{g[j],g[s]+g[j-s]}),且(s)是合法状态。

    这样我们先用斯坦纳树的方法求出(f),从而得到初始的(g).

    显然(g[j]=mathrm{min}{f[i][j]})

    然后枚举当前状态(j)以及当前状态的合法子集更新(g).

    最终(g[S])即为答案((S)是题中给出的点集)。

    代码

    #include<bits/stdc++.h>
    #define MAXN 20010
    #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,D,f[MAXN][1<<8],g[1<<8],head[MAXN],cnt;
    inline void Add_Edge(int from,int to,int val){
    	e[++cnt].t=to;e[cnt].next=head[from];head[from]=cnt;e[cnt].v=val;
    	e[++cnt].t=from;e[cnt].next=head[to];head[to]=cnt;e[cnt].v=val;
    } 
    queue<int>q;
    bool vis[MAXN];
    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){
    	for(int i=0;i<D;i++){
    		if(((S>>i)&1)&&!((S>>(D+i))&1))return 0;
    	}
    	return 1;
    }
    int x,y,z;
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("bzoj4774.in","r",stdin);
    	freopen("bzoj4774.out","w",stdout);
    	#endif
    	N=qr();M=qr();D=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<=D;i++)f[i][(1<<(i-1))]=f[N-i+1][(1<<(D+i-1))]=0;
    	for(int i=0,ed=(1<<(D+D));i<ed;i++){
    		for(int j=1;j<=N;j++){
    			for(int s=i&(i-1);s;s=i&(s-1)){
    				f[j][i]=min(f[j][i],f[j][s]+f[j][i-s]);
    			}
    		}
    		Spfa(i);
    		for(int j=1;j<=N;j++)g[i]=min(g[i],f[j][i]);
    	}
    	for(int i=0,ed=(1<<(D+D));i<ed;i++){
    		for(int s=i&(i-1);s;s=i&(s-1)){
    			if(Check(s)&&Check(i-s))g[i]=min(g[i],g[s]+g[i-s]);
    		}
    	}
    	printf("%d
    ",g[(1<<(D+D))-1]==INF?-1:g[(1<<(D+D))-1]);
    	return 0;
    }
    
  • 相关阅读:
    6 开发工具IDE-pycharm
    5 循环控制
    react native 遇到的坑
    代码缩略图插件
    JEECMS-自定义标签[list]
    Jeecms自定义标签用法[单个内容]
    ReactNative环境搭建
    修改浏览器accept使支持@ResponseBody
    [转]MyEclipse for Spring2014破解
    js正则验证手机号
  • 原文地址:https://www.cnblogs.com/lrj998244353/p/8830690.html
Copyright © 2011-2022 走看看