修路

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. 【数据库】 SQLite 语法

    [数据库] SQLite 语法 一 . 创建数据库 1. 只需创建数据库,只需创建文件,操作时将连接字符串指向该文件即可 2. 连接字符串 : data source = FilePath; 不能加密 ...

  2. js鼠标事件相关知识

    1.mousedown->mouseup依次触发后相当于click事件 2.除了mouseenter和mouseleave外,其它的鼠标事件都是冒泡的 3.mouseover和mouseout事 ...

  3. Loadrunner11.0安装与简单使用

    公司开发了APP或者微信小程序啊什么的,都会先进行性能测试,而性能测试一般肯定会来测试接口的压测,并发.Loadrunner是一个很强大的测试工具,它是一种预测系统行为和性能的负载测试工具.通过以模拟 ...

  4. 剑指offer-链表中倒数第K个结点14

    题目描述 输入一个链表,输出该链表中倒数第k个结点. class Solution: def FindKthToTail(self, head, k): # write code here res=[ ...

  5. argos3-simulator

    如何修改控制器: CVector2: class CVector2 { friend class CRotationMatrix2; friend class CTransformationMatri ...

  6. Unity UGUI 图片 轴对称效果 减少资源

    制作UI的过程中,为了节省资源,对称的图一般美术切一半给我们 手动拼图 有时会出现拼接处出现裂缝或重叠 调整大小时也不方便 得一块一块调整 所以就用BaseMeshEffect 的ModifyMesh ...

  7. ssh问题_1

    昨天配置了虚拟机的ssh,可以相互连接,但是今天早上就不行了,遇到如下错误 [slave1@hadoop ~]$ scp .ssh/id_rsa.pub master@hadoop.master:~/ ...

  8. STL中list的erase()方法

    http://www.cnblogs.com/gshlsh17/ rase()方法是删除iterator指定的节点  但是要注意的是在执行完此函数的时候iterator也被销毁了   这样的话关于it ...

  9. webstorm-前端javascript开发神器中文教程和技巧分享(转)

    webstorm是一款前端javascript开发编辑的神器,此文介绍webstorm的中文教程和技巧分享. webstorm8.0.3中文汉化版下载: 百度网盘下载:http://pan.baidu ...

  10. 延迟加载(Lazyload)三种实现方式

    定义:延迟加载也称为惰性加载,即在长网页中延迟加载图像.用户滚动到它们之前,视口外的图像不会加载.这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快.在某些情况下,它还可以帮助减少服务器负载. ...