管道连接 bzoj-4006 JLOI-2015

题目大意:给定一张$n$个节点$m$条边的带边权无向图。并且给定$p$个重要节点,每个重要节点都有一个颜色。求一个边权和最小的边集使得颜色相同的重要节点互相连通。

注释:$1\le c_i \le p \le 10$,$1\le u_i,v_i,d_i\le n\le 10^3$,$0\le m\le 3\cdot 10^3$,$0\le w_i\le 2\cdot 10^4$。其中$c_i$和$d_i$分别是第$i$个节点的颜色和编号。


想法:发现这鬼东东和斯坦纳树很像啊。

我们先对$p$个点求出斯坦纳树,存入$f[s][i]$表示状态为$s$的重要节点被选取当前选到了$i$。

那么我们考虑怎么对这个颜色进行处理?

因为颜色个数也比较少对吧,不难想到状压$dp$(我当时就没想到$qwq$)。

$g[s]$表示状态为$s$的颜色满足条件(每个颜色属于$s$都已经内部连通)的最小代价。

转移的话,我们先设一个$now$表示的是所有颜色属于$s$的重要节点的编号的状态,那么$g[s]$就可以从$f[now][j]$转移过来($j$是$now$中的任意一个节点。)

这个就表示$s$代表的所有重要节点互相连通的方案数。

因为不同的颜色互相可以不连通,所以我们枚举$s$的子集$t$,用$g[t]+g[s-t]$转移到$s$即可。

时间复杂度$O(3^p\cdot n + 2^p \cdot m logn)$。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 1100
#define M 3010
using namespace std;
int head[N],to[M<<1],val[M<<1],nxt[M<<1],tot;
int c[20],d[20],f[N][N],g[N];
bool vis[N][N];
priority_queue<pair<int,int> >q; // 堆优化Dij
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {int x=0,f=1; char c=nc(); while(c<48) {if(c=='-') f=-1; c=nc();} while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;}
inline void add(int x,int y,int z) {to[++tot]=y; val[tot]=z; nxt[tot]=head[x]; head[x]=tot;}
int main()
{
memset(f,0x3f,sizeof f);
int n=rd(),m=rd(),p=rd();
for(int i=1;i<=m;i++) {int x=rd(),y=rd(),z=rd(); add(x,y,z),add(y,x,z);}
for(int i=1;i<=p;i++) c[i]=rd(),d[i]=rd(); // 分别记录节点颜色和编号
for(int i=1;i<=p;i++) f[1<<(i-1)][d[i]]=0;
int all=(1<<p)-1; // 表示所有重要节点的全集
for(int i=1;i<=all;i++) // 斯坦纳树
{
for(int j=i;j;j=(j-1)&i)
{
for(int k=1;k<=n;k++)
{
f[i][k]=min(f[i][k],f[j][k]+f[i-j][k]);
}
}
for(int j=1;j<=n;j++) q.push(make_pair(-f[i][j],j));
while(!q.empty())
{
int x=q.top().second; q.pop();
if(vis[i][x]) continue;
vis[i][x]=true;
for(int j=head[x];j;j=nxt[j]) if(f[i][to[j]]>f[i][x]+val[j])
{
f[i][to[j]]=f[i][x]+val[j];
q.push(make_pair(-f[i][to[j]],to[j]));
}
}
}
memset(g,0x3f,sizeof g);
for(int i=1;i<=all;i++) // 状压dp
{
int now=0; for(int j=1;j<=p;j++)
{
if(i&(1<<(c[j]-1)))
{
now|=(1<<(j-1));
}
}
for(int j=1;j<=n;j++) g[i]=min(g[i],f[now][j]);
for(int j=i;j;j=(j-1)&i) g[i]=min(g[i],g[j]+g[i-j]);
}
cout << g[all] << endl ;
return 0;
}

小结:这个斯坦纳树的题还是非常好的。不仅需要对斯坦纳树有点理解,对状压$dp$的使用还得比较灵活。

我当时就没想到后一步的状压$dp$。

[bzoj4006][JLOI2015]管道连接_斯坦纳树_状压dp的更多相关文章

  1. BZOJ 4006 Luogu P3264 [JLOI2015]管道连接 (斯坦纳树、状压DP)

    题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4006 (luogu)https://www.luogu.org/probl ...

  2. 【bzoj4006】[JLOI2015]管道连接(斯坦纳树+dp)

    题目链接 题意: 给出\(n\)个点,\(m\)条边,同时给出\(p\)个重要的点以及对应特征. 现在要选出一些边,问使得这\(p\)个所有特征相同的点相连,问最小代价. 思路: 斯坦纳树的应用场景一 ...

  3. bzoj 4006 [JLOI2015]管道连接(斯坦纳树+状压DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4006 [题意] 给定n点m边的图,连接边(u,v)需要花费w,问满足使k个点中同颜色的 ...

  4. BZOJ 4006 [JLOI2015]管道连接(斯坦纳树+子集DP)

    明显是一道斯坦纳树的题. 然而这题只需要属性相同的点互相连接. 我们还是照常先套路求出\(ans[s]\). 然后对\(ans[s]\)做子集DP即可. 具体看代码. #include<iost ...

  5. 洛谷P3264 [JLOI2015]管道连接(斯坦纳树)

    传送门 感觉对斯坦纳树还是有很多疑惑啊…… 等到时候noip没有爆零的话再回来填坑好了 //minamoto #include<iostream> #include<cstdio&g ...

  6. [JLOI2015]管道连接(斯坦纳树)

    [Luogu3264] 原题解 多个频道,每个频道的关键点要求相互联通 详见代码,非常巧妙 #include<cstdio> #include<iostream> #inclu ...

  7. 【ZJOI2017 Round1练习&BZOJ4774】D3T2 road(斯坦纳树,状压DP)

    题意: 对于边带权的无向图 G = (V, E),请选择一些边, 使得1<=i<=d,i号节点和 n − i + 1 号节点可以通过选中的边连通, 最小化选中的所有边的权值和. d< ...

  8. BZOJ_4006_[JLOI2015]管道连接_斯坦纳树

    BZOJ_4006_[JLOI2015]管道连接_斯坦纳树 题意: 小铭铭最近进入了某情报部门,该部门正在被如何建立安全的通道连接困扰. 该部门有 n 个情报站,用 1 到 n 的整数编号.给出 m ...

  9. BZOJ_2595_[Wc2008]游览计划_斯坦纳树

    BZOJ_2595_[Wc2008]游览计划_斯坦纳树 题意: 分析: 斯坦纳树裸题,有几个需要注意的地方 给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值 方案记录比较麻烦,两 ...

随机推荐

  1. 深入解析Web Services

    SOA,面向服务器建构,是一款架构,这几年虽然没前几年那么流行,但是还是有很多企业在用,而Web Services是目前适合做SOA的主要技术之一,通过使用Web Services,应用程序可以对外发 ...

  2. java程序在一个电脑上只启动一次,只开一个进程

    方案1: 单进程程序可以用端口绑定.程序启动的时候可以尝试看该端口是否已经被占用,如果占用则程序已经启动. 方案2:你可以在java程序中创建一个隐藏文件,程序退出的时候删除这个文件.这样在程序启动的 ...

  3. QT_4_QpushButton的简单使用_对象树

    QpushButton的简单使用 1.1 按钮的创建 QPushButton *btn = new QPushButton; 1.2 btn -> setParent(this);设置父窗口 1 ...

  4. python之str (字符型)

    用途: 存储少量的数据,+ *int 切片, 其他操作方法 切片还是对其进行任何操作,获取的内容全部是strl类型 存储数据单一 格式: 在python中用引号引起来的就是字符串 '今天吃了没?' 1 ...

  5. spring mvc poi excel

    Util类 package com.common.util; public class ExportUtil { private XSSFWorkbook wb = null; private XSS ...

  6. JS数组专题1️⃣ ➖ 数组扁平化

    一.什么是数组扁平化 扁平化,顾名思义就是减少复杂性装饰,使其事物本身更简洁.简单,突出主题. 数组扁平化,对着上面意思套也知道了,就是将一个复杂的嵌套多层的数组,一层一层的转化为层级较少或者只有一层 ...

  7. Visual C++中error spawning cl.exe错误的两种解决方法.

    可能很多人在安装VC 6.0后有过点击“Compile”或者“Build”后被出现的 “Compiling... ,Error spawning cl.exe”错误提示给郁闷过.很多人的 选择是重装, ...

  8. Ubuntu14.04环境下Qt5.5以上版本无法输入中文的解决教程

    1.前言 由于Qt5.4之后对之前的Qt5版本不再二进制兼容,所以网上很多简单的旧的办法已经失效了,所以本教程的办法是重新编译fcitx-qt5,生成最新的libfcitxplatforminputc ...

  9. mysql5.7配置

    my3306.cnf [client] port = 3306   #端口socket = /data/mysql3306/mysql3306.sock   #mysql以socket方式运行的soc ...

  10. php 快速导出大量CSV文件

    原文链接 https://segmentfault.com/a/1190000005366832 /** * 导出excel(csv) * @data 导出数据 * @headlist 第一行,列名 ...