题意:给出一个无向图,和四对数据。每对数据分别为图中的两个点。要求添加一些边,使每对点都能连通,让总边权最小。

分析:POJ3123、NWERC2006原题,《acm国际大学生程序设计竞赛:题目与解读》P564。斯坦纳森林模板题,把所有的集合放在一起,做一遍斯坦纳树,然后对所有集合做一遍子集合并dp。斯坦纳树的转移方程有两重:第一重,先通过连通状态的子集进行转移。dp[i][state]=min{ dp[i][subset1]+dp[i][subset2] } ,枚举子集的技巧可以用 for(sub=(state-1)&state;sub;sub=(sub-1)&state)。第二重,在当前枚举的连通状态下,对该连通状态进行松弛操作。dp[i][state]=min{ dp[i][state], dp[j][state]+e[i][j] }。复杂度 O(n*3^k+c*E*2^k)。k为要求连通的点数,c为SPFA复杂度中的常数,E为边的数量,但几乎达不到全部边的数量,甚至非常小。3^k来自于子集的转移,sum{C(i,n)*2^i} (1<=i<=n),用二项式展开求一下和。

斯坦纳树入门参考https://www.cnblogs.com/ECJTUACM-873284962/p/7643445.html#autoid-0-1-0。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;int n, m, cnt, u, v, w;
int status;///表示0~n号节点都被选择时的状态+1
int s[40], nt[2009], e[2009], val[2009];
int dis[40][1000], vis[40], ans[1000], flag[1000];
///dis[i][j]表示以i节点为根选择点集状态为j时的最小值;vis[i][j]表示i节点为点集j时是否在队列中
queue<int>q;
map<string, int>mp;/// 城市名和节点编号的对应关系
char s1[30], s2[30];///初始化
void init()
{memset(vis, 0, sizeof vis);memset(s, -1, sizeof s);mp.clear();cnt = 0;status = 1 << 8;for (int i = 1; i <= n; i++)for (int j = 0; j < status; j++)dis[i][j] = INF;
}///SPFA进行松弛
void SPFA(int sta)
{while (!q.empty()){int pre = q.front();q.pop();vis[pre] = 0;for (int i = s[pre]; ~i; i = nt[i]){if (dis[pre][sta] + val[i] < dis[e[i]][sta]){dis[e[i]][sta] = dis[pre][sta] + val[i];if (!vis[e[i]]){vis[e[i]] = 1;q.push(e[i]);}}}}
}
/// 斯坦纳树核心代码(状压dp)
void Steiner_Tree()
{for (int i = 0; i < status; i++){/// 第一重,先通过连通状态的子集进行转移。/// dp[i][state]=min{ dp[i][subset1]+dp[i][subset2] }for (int j = 1; j <= n; j++){for (int k = i; k; k = (k - 1) & i)dis[j][i] = min(dis[j][i], dis[j][k] + dis[j][i - k]);if (dis[j][i] != INF){q.push(j);vis[j] = 1;}}/// 第二重,在当前枚举的连通状态下,对该连通状态进行松弛操作。/// dp[i][state]=min{ dp[i][state], dp[j][state]+e[i][j] }SPFA(i);}
}/// 检查点对是否在k状态下的存在性是否一样 存在性不一致时返回真需要进行子集合并
int check(int k)
{for (int i = 0; i < 4; i++)if ((k >> i & 1) ^ (k >> (i + 4) & 1)) return 0;return 1;
}/// (斯坦纳森林解法)把所有的集合放在一起,做一遍斯坦纳树,然后对所有集合做一遍子集合并dp。
int main()
{while (~scanf("%d %d", &n, &m) && (n + m)){init();for (int i = 1; i <= n; i++) scanf("%s", s1), mp[s1] = i;for (int i = 1; i <= m; i++){scanf("%s%s%d", s1, s2, &w);u = mp[s1], v = mp[s2];nt[cnt] = s[u], s[u] = cnt, e[cnt] = v, val[cnt++] = w;nt[cnt] = s[v], s[v] = cnt, e[cnt] = u, val[cnt++] = w;}for (int i = 1; i <= 8; i++) ///处理四对点对{scanf("%s", s1);int temp = ((i & 1) ? i / 2 : i / 2 + 3); /// 0-4 1-5 2-6 3-7 一一对应dis[mp[s1]][1 << temp] = 0;}Steiner_Tree();/// 求出8个点(四个点对)都相连的花费for (int i = 0; i < status; i++){flag[i] = check(i), ans[i] = INF;for (int j = 1; j <= n; j++) ans[i] = min(ans[i], dis[j][i]);}///合并子集for (int i = 0; i < status; i++)if (flag[i])///需要合并时{///枚举子集转移for (int j = i; j; j = (j - 1)&i)if (flag[j] && flag[i - j]) ///转移条件ans[i] = min(ans[i], ans[j] + ans[i - j]);}printf("%d\n", ans[status - 1]);}return 0;
}

2019 ICPC 南昌邀请赛 A-Attack(斯坦纳树)相关推荐

  1. 2019 ICPC南昌邀请赛比赛游记 队伍名:莫比乌斯

    南昌队伍是学长临时组的 飞的那天和学长们坐 6.1的飞机 川航还发了棒棒糖 下飞机就落在了座位上了 然后难道大暴雨 我鞋子都湿了 我们和学长去了酒店 酒店是很有情趣味道 滑稽 于是拍下了学长的背影 学 ...

  2. 2019 ICPC南昌邀请赛网络赛比赛过程及题解

    解题过程 中午吃饭比较晚,到机房lfw开始发各队的账号密码,byf开始读D题,shl电脑卡的要死,启动中...然后听到谁说A题过了好多,然后shl让blf读A题,A题blf一下就A了.然后lfw读完M ...

  3. 2019 icpc南昌邀请赛 G Winner

    题目链接:https://nanti.jisuanke.com/t/40259 Ichuan really likes to play games, so he organized a game co ...

  4. 2019 ICPC全国邀请赛(西安)I. Cracking Password(序列检验,BSGS,细节题)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 2019 ICPC全国邀请赛(西安)I. Cracking Password Weblink http ...

  5. 2019 ICPC 南昌网络赛 H. The Nth Item

    2019 ICPC 南昌网络赛 H. The Nth Item 题目大意:已知一个数列F(n): F(0)=0,F(1)=1 F(n)=3∗F(n−1)+2∗F(n−2),(n≥2) ​ 给你一个操作 ...

  6. [学习笔记]斯坦纳树

    处理一种这样的问题: 斯坦纳树问题是组合优化问题,与最小生成树相似,是最短网络的一种.最小生成树是在给定的点集和边中寻求最短网络使所有点连通.而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络 ...

  7. bzoj1402 Ticket to Ride 斯坦纳树 + 状压dp

    给定\(n\)个点,\(m\)条边的带权无向图 选出一些边,使得\(4\)对点之间可达,询问权值最小为多少 \(n \leqslant 30, m \leqslant 1000\) 首先看数据范围,\ ...

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

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

  9. [WC2008]游览计划(斯坦纳树)

    [Luogu4294] 题解 : 斯坦纳树 \(dp[i][j]\) 表示以\(i\)号节点为根,当前状态为\(j\)(与\(i\)连通的点为\(1\)) 当根\(i\)不改变时状态转移方程是: \( ...

最新文章

  1. toString()、String.valueOf、(String)强转,如何抉择,你真的了解吗
  2. iOS获取最上层控制器
  3. LCD正向扫描和反向扫描
  4. Telerik for Winform 2010版下载、安装、初次使用
  5. 【Linux】scp“免密” 远程copy较多文件
  6. 2019你还没搭建个人博客吗?进来看看
  7. scala通过JDBC进行数据库操作
  8. 百度AI快车道深圳实战班启动,用极致技术打造实用产品
  9. html绘制圆形和弧形的代码,html5 canvas用来绘制弧形的代码实现
  10. 如何在Azure中配置SQL Server 2008 R2故障转移群集实例
  11. 转载--Defunct僵尸进程
  12. Linux运维基础入门知识
  13. 计算机应用基础南丁格尔,关于单元基础训练的习题
  14. 华沙理工大学语言c1,留学波兰华沙理工大学:一个让人轻易就爱上的地方
  15. kaggle实战:Titanic
  16. 城市云脑研究之三,人工智能在城市云脑建设中的地位与作用
  17. HIVE --- Metastore
  18. 为知笔记(PC端) 康奈尔模板各栏间距调整
  19. 小米 红米4(标准版)线刷兼救砖_解账户锁_纯净刷机包_教程
  20. 养老保险不到60岁能领吗

热门文章

  1. HDMI-CEC 控制服务
  2. cnn程序流程图_CNN 训练流程
  3. MyBatis开启mapUnderscoreToCamelCase配置驼峰转换
  4. 微前端的现状以及趋势
  5. 菜鸟架构师爆肝分享!云计算ACP考试学习资料!!
  6. makefile编译时候出现:commands commence before first target
  7. 【电路设计】AD进行多层板绘制
  8. Pepper/Nao初级教程:第三章 Choregraphe用法 (Pepper与Nao本质是同一种机器人)
  9. word2007中的论文页码设置
  10. Wasm 玩出花?在浏览器中运行虚拟机!