修路

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. mysql 大数据分页查询优化

    应用场景: 当有一张表的数据非常大,需要使用到分页查询,分页查询在100w条后查询效率非常低: 解决方案: 1.业务层解决:只允许用户翻页一百页以内,十条一页: 2.使用where id > 5 ...

  2. JS 客户端检测

    能力检测 能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力. 能力检测需要注意两点: 先检测达成目的的最常用的特性.因为先检测最常用的特性可以保证代码最优化,因为在多数情况下都可以避免测试多个 ...

  3. 标志寄存器PSW和汇编条件转移指令解释

    标志寄存器PSW 标志寄存器PSW(程序状态字寄存器PSW)   标志寄存器PSW是一个16为的寄存器.它反映了CPU运算的状态特征并且存放某些控制标志.8086使用了16位中的9位,包括6个状态标志 ...

  4. ubuntu自带的ibus输入法问题解决方法

    ubuntu自带的ibus有点问题,输入字的时候不知道是个什么模式. 在网上搜到一个解决方法. 终端下执行: ibus-daemon -drx 然后切换到拼音输入法,就正常了. 写下作为记录.

  5. MySQL高可用之PXC安装部署

      Preface       Today,I'm gonna implement a PXC,Let's see the procedure.   Framework   Hostname IP P ...

  6. Spotlight on MySQL

    聚光灯在MySQL 1.Sessios会话Total Users:总用户数前连接到MySQL服务器的用户会话总数Active Users:活跃用户此控件表示连接到当前正在执行SQL语句或其他数据库请求 ...

  7. HDFS常用文件操作

    put 上传文件    hadoop fs -put wordcount.txt   /data/wordcount/ text 查看文件内容   hadoop fs -text /output/wo ...

  8. CentOS安装Harbor

    CentOS版本:7.4 Harbor版本:1.5.0 Docker版本:1.12.6 Docker Compose版本:1.21.2 一.安装Harbor(http方式,80端口) 1.安装Dock ...

  9. Linux 简单socket实现TCP通信

    服务器端代码 #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <stri ...

  10. viterbi维特比算法和隐马尔可夫模型(HMM)

    隐马尔可夫模型(HMM) 原文地址:http://www.cnblogs.com/jacklu/p/7753471.html 本文结合了王晓刚老师的ENGG 5202 Pattern Recognit ...