zoukankan      html  css  js  c++  java
  • 【BZOJ4774/4006】修路/[JLOI2015]管道连接 斯坦纳树

    【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[S][i]表示已经连通的关键点状态为S,当前位于点i的最小权值和。转移就是斯坦纳树。

    再设g[S]表示已经连通的关键点状态为S的最小权值和。只有当S保证所有的关键点对的连通状态相同时,才可以从f[S][..]更新到g[S],最后对g数组跑枚举子集的DP即可。

    P.S.我至今才会枚举子集的正确姿势~~~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <utility>
    #define mp(A,B) make_pair(A,B)
    using namespace std;
    int n,m,d,cnt,now,tot;
    int f[1<<8][10010],to[20010],next[20010],val[20010],head[10010],vis[10010],p[20],Log[1<<8],ref[1<<8],g[1<<8];
    priority_queue<pair<int,int> > q;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    }
    inline void dij(int S,int x)
    {
    	q.push(mp(-f[S][x],x));
    	int i,u;
    	now++;
    	while(!q.empty())
    	{
    		u=q.top().second,q.pop();
    		if(vis[u]==now)	continue;
    		vis[u]=now;
    		for(i=head[u];i!=-1;i=next[i])	if(f[S][to[i]]>f[S][u]+val[i])
    			f[S][to[i]]=f[S][u]+val[i],q.push(mp(-f[S][to[i]],to[i]));
    	}
    }
    int main()
    {
    	int i,a,b,c,x,y;
    	n=rd(),m=rd(),d=rd();
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=m;i++)	a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
    	for(i=0;i<2*d;i++)	Log[1<<i]=i;
    	memset(f,0x3f,sizeof(f)),memset(g,0x3f,sizeof(g));
    	for(i=1;i<=d;i++)
    	{
    		f[1<<(i-1)][i]=0,dij(1<<(i-1),i);
    		f[1<<(d+i-1)][n-i+1]=0,dij(1<<(d+i-1),n-i+1);
    	}
    	for(x=1;x<(1<<(2*d));x++)
    	{
    		for(tot=0,y=x;y;y-=y&-y)	p[tot++]=y&-y;
    		for(y=1;y<(1<<tot);y++)
    		{
    			ref[y]=ref[y^(y&-y)]|p[Log[y&-y]];
    			for(i=1;i<=n;i++)	if(f[x][i]>f[ref[y]][i]+f[x^ref[y]][i])
    				f[x][i]=f[ref[y]][i]+f[x^ref[y]][i];
    		}
    		for(i=1;i<=n;i++)	dij(x,i);
    	}
    	for(x=1;x<(1<<d);x++)	for(i=1;i<=n;i++)	g[x]=min(g[x],f[(x<<d)|x][i]);
    	for(x=1;x<(1<<d);x++)
    	{
    		for(tot=0,y=x;y;y-=y&-y)	p[tot++]=y&-y;
    		for(y=1;y<(1<<tot);y++)
    		{
    			ref[y]=ref[y^(y&-y)]|p[Log[y&-y]];
    			g[x]=min(g[x],g[ref[y]]+g[x^ref[y]]);
    		}
    	}
    	if(g[(1<<d)-1]==0x3f3f3f3f)	printf("-1");
    	else	printf("%d",g[(1<<d)-1]);
    	return 0;
    }
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <utility>
    #define mp(A,B) make_pair(A,B)
    using namespace std;
    int n,m,d,cnt,now;
    int to[6010],next[6010],val[6010],head[1010],f[1<<10][1010],g[1<<10],p[15],w[15],vis[1<<10];
    priority_queue<pair<int,int> > q;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    }
    inline void dij(int S,int x)
    {
    	q.push(mp(-f[S][x],x));
    	int i,u;
    	now++;
    	while(!q.empty())
    	{
    		u=q.top().second,q.pop();
    		if(vis[u]==now)	continue;
    		vis[u]=now;
    		for(i=head[u];i!=-1;i=next[i])	if(f[S][to[i]]>f[S][u]+val[i])
    			f[S][to[i]]=f[S][u]+val[i],q.push(mp(-f[S][to[i]],to[i]));
    	}
    }
    int main()
    {
    	n=rd(),m=rd(),d=rd();
    	int i,j,a,b,c,x,y;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=m;i++)	a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
    	memset(f,0x3f,sizeof(f)),memset(g,0x3f,sizeof(g));
    	for(i=0;i<d;i++)	w[i]=rd(),p[i]=rd(),f[1<<i][p[i]]=0,dij(1<<i,p[i]);
    	for(x=1;x<(1<<d);x++)
    	{
    		for(y=(x-1)&x;y;y=(y-1)&x)	for(i=1;i<=n;i++)	f[x][i]=min(f[x][i],f[y][i]+f[x^y][i]);
    		for(i=1;i<=n;i++)	dij(x,i);
    	}
    	for(x=1;x<(1<<d);x++)	for(i=1;i<=n;i++)	g[x]=min(g[x],f[x][i]);
    	for(x=1;x<(1<<d);x++)
    	{
    		for(i=0;i<d;i++)	for(j=0;j<i;j++)	if(w[i]==w[j]&&((x>>i)&1)!=((x>>j)&1))	g[x]=0x3f3f3f3f;
    	}
    	for(x=1;x<(1<<d);x++)	for(y=(x-1)&x;y;y=(y-1)&x)	g[x]=min(g[x],g[y]+g[x^y]);
    	printf("%d",g[(1<<d)-1]);
    	return 0;
    }
  • 相关阅读:
    JMeter4.0的单机压测和集群压测简介
    接口自动化测试,完整入门篇
    jmeter实战---正则提取器
    压测必经之路,解读JMeter分布式
    JMeter线程组参数含义
    jmeter生成HTML性能测试报告
    SPP-Net、Atrous Convolution以及ASPP by Rose
    使用CNN进行角度估计
    Java相关书籍分享
    Code Conventions for the Java
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7898576.html
Copyright © 2011-2022 走看看