修路

Time Limit: 20 Sec  Memory Limit: 256 MB

Description

  

Input

  

Output

  仅一行一个整数表示答案。

Sample Input

  5 5 2
  1 3 4
  3 5 2
  2 3 1
  3 4 4
  2 4 3

Sample Output

  9

HINT

  

Main idea

  给定若干对点,选择若干边,询问满足每对点都连通的最小代价。

Solution

  发现 d 非常小,所以我们显然可以使用斯坦纳树来求解。

  斯坦纳树是用来解决这种问题的:给定若干关键点,求使得关键点连通的最小代价

  我们可以令 f[i][opt] 表示以 i 为根时,关键点连通态为opt的最小代价。(以二进制表示是否连通)

  然后我们就可以用两种方法来更新 f[i][opt]:

  1. 设定集合x,y,x∪y=opt且x∩y=∅,那么我们显然就可以将用x,y合并来更新opt,
  2. 若 f[j][opt] 中opt = f[i][opt]中opt,那么我们就可以以连边方式合并两个集合,这种合并方式显然可以用最短路实现,使得答案更优。

  然后我们就可以求出所有状态的f[i][opt],接下来再利用DP,求解。

  定义Ans[opt]表示连通态为opt时最小代价,如果对应点同时连通或不连通则可以更新,枚举所有情况就可以求出答案了。

Code

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std; const int ONE = ;
const int MOD = 1e9+; int n,m,d;
int x,y,z;
int a[ONE];
int next[ONE],first[ONE],go[ONE],w[ONE],tot;
int All,f[ONE/][],INF;
int q[],vis[ONE],tou,wei;
int Ans[]; int get()
{
int res=,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} void Add(int u,int v,int z)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v; w[tot]=z;
next[++tot]=first[v]; first[v]=tot; go[tot]=u; w[tot]=z;
} namespace Steiner
{
void pre()
{
memset(f,,sizeof(f)); INF=f[][];
int num = ;
for(int i=;i<=d;i++) f[i][<<num] = , num++;
for(int i=n-d+;i<=n;i++) f[i][<<num] = , num++;
All = (<<num) - ;
} void Spfa(int opt)
{
while(tou<wei)
{
int u=q[++tou];
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(f[v][opt] > f[u][opt] + w[e])
{
f[v][opt] = f[u][opt] + w[e];
if(!vis[v])
{
vis[v] = ;
q[++wei] = v;
}
}
}
vis[u] = ;
}
} void Deal()
{
for(int opt=;opt<=All;opt++)
{
for(int i=;i<=n;i++)
{
for(int sub=opt;sub;sub=(sub-) & opt)
f[i][opt] = min(f[i][opt],f[i][sub]+f[i][opt^sub]);
if(f[i][opt] != INF)
{
q[++wei] = i;
vis[i] = ;
}
}
Spfa(opt);
}
}
} bool Check(int opt)
{
for(int i=,j=(d<<)-; i<d; i++,j--)
if( ((opt & (<<i))== ) != ((opt & (<<j))==) )
return ;
return ;
} int main()
{
n=get(); m=get(); d=get();
for(int i=;i<=m;i++)
{
x=get(); y=get(); z=get();
Add(x,y,z);
} Steiner::pre();
Steiner::Deal(); memset(Ans,,sizeof(Ans));
for(int opt=;opt<=All;opt++)
if(Check(opt))
{
for(int i=;i<=n;i++)
Ans[opt] = min(Ans[opt], f[i][opt]);
} for(int opt=;opt<=All;opt++)
for(int sub=opt;sub;sub=(sub-) & opt)
Ans[opt] = min(Ans[opt], Ans[sub]+Ans[opt^sub]); if(Ans[All] == INF) printf("-1");
else printf("%d",Ans[All]);
}

【BZOJ4774】修路 [斯坦纳树]的更多相关文章

  1. 「长乐集训 2017 Day8」修路 (斯坦纳树)

    题目描述 村子间的小路年久失修,为了保障村子之间的往来,AAA君决定带领大家修路. 村子可以看做是一个边带权的无向图GGG, GGG 由 nnn 个点与 mmm 条边组成,图中的点从 1∼n1 \si ...

  2. 【BZOJ4774】修路(动态规划,斯坦纳树)

    [BZOJ4774]修路(动态规划,斯坦纳树) 题面 BZOJ 题解 先讲怎么求解最小斯坦纳树. 先明白什么是斯坦纳树. 斯坦纳树可以认为是最小生成树的一般情况.最小生成树是把所有给定点都要加入到联通 ...

  3. 【BZOJ4774/4006】修路/[JLOI2015]管道连接 斯坦纳树

    [BZOJ4774]修路 Description 村子间的小路年久失修,为了保障村子之间的往来,法珞决定带领大家修路.对于边带权的无向图 G = (V, E),请选择一些边,使得1 <= i & ...

  4. 初涉斯坦纳树&&bzoj4774: 修路

    斯坦纳树的基础应用 斯坦纳树有什么用 个人一点粗浅理解…… 最基本形式的斯坦纳树问题(以下简称母问题):给定图G和一个关键点集V.求在G中选取一个权值最小(这里权值可以有很多变式)的边集E使V中的点两 ...

  5. 【BZOJ2595】游览计划(状压DP,斯坦纳树)

    题意:见题面(我发现自己真是越来越懒了) 有N*M的矩阵,每个格子有一个值a[i,j] 现要求将其中的K个点(称为关键点)用格子连接起来,取(i,j)的费用就是a[i,j] 求K点全部连通的最小花费以 ...

  6. HDU 4085 斯坦纳树

    题目大意: 给定无向图,让前k个点都能到达后k个点(保护地)中的一个,而且前k个点每个需要占据后k个中的一个,相互不冲突 找到实现这个条件达到的选择边的最小总权值 这里很容易看出,最后选到的边不保证整 ...

  7. hdu4085 Peach Blossom Spring 斯坦纳树,状态dp

    (1)集合中元素表示(1<<i), i从0开始 (2)注意dp[i][ss] = min(dp[i][ss], dp[i][rr | s[i]] + dp[i][(ss ^ rr) | s ...

  8. hdu 3311 斯坦纳树

    思路:虚拟一个0号节点,将每个点建一条到0号节点的边,权值为挖井需要的价值.并要保证0号节点同另外n个寺庙一样被选择即可. 然后就是求斯坦纳树了. #include<map> #inclu ...

  9. HDU 3311 Dig The Wells(斯坦纳树)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3311 [题意] 给定k座庙,n个其他点,m条边,点权代表挖井费用,边权代表连边费用,问使得k座庙里 ...

随机推荐

  1. android中的文件(图片)上传

    android中的文件(图片)上传其实没什么复杂的,主要是对 multipart/form-data 协议要有所了解. 关于 multipart/form-data 协议,在 RFC文档中有详细的描述 ...

  2. 签名APK后仍然出现INSTALL_PARSE_FAILED_NO_CERTIFICATES的解决方案

    修改apk里的dex并且修复后重新打包进apk里,使用signapk.jar签名后安装仍然出现INSTALL_PARSE_FAILED_NO_CERTIFICATES,搜了很久,使用了多种方法签名仍然 ...

  3. jmeter无法启动的解决办法

    jmeter下载地址: 链接: https://pan.baidu.com/s/15YhiPH-kNVxISEZ4Mxf_WA     提取码: 25sv jdk 8.0 下载地址: 链接: http ...

  4. TW实习日记:第15天

    今天又是修修补补的一天,不过最开心的是因为项目比较特殊,有自己的后端服务器,有一些接口相关的bug可以让我直接写Java代码,终于可以碰一碰Java了哈哈.有好几个bug都是之前的人粗心设置了多余或者 ...

  5. COJ 2192: Wells弹键盘 (dp)

    2192: Wells弹键盘 Description Wells十分羡慕和佩服那些会弹钢琴的人比如子浩君,然而Wells只会弹键盘…… Wells的键盘只有10个键,从1,2,3,……,9,0,如下图 ...

  6. Daily Scrum02 12.01

    今天是2013年12月的第一天,希望大家都有一个新的开始,一起努力!     Member Today's Task Tomorrow's Task 李孟 Task 856: 熟悉单元测试方法熟悉单元 ...

  7. c# 生成dll

    进入项目属性栏里,选择输出类型为类库.

  8. python中locals和globals函数

    参考:http://www.cnblogs.com/wanxsb/archive/2013/05/07/3064783.html Python有两个内置的函数,locals() 和globals(), ...

  9. C++常用STL

    目录 C++ 常用STL整理 容器和配接器 list(链表) stack(栈) queue(队列) priority_queue(优先队列) set(集合) vector(向量) map&&a ...

  10. C语言单元测试

    转自http://blog.csdn.net/colin719/article/details/1420583 对于敏捷开发来说,单元测试必不可少,对于Java开发来说,JUnit非常好,对于C++开 ...