Codeforces 700 C. Break Up(Tarjan求桥)
题意
给你一个有 \(n\) 个点, \(m\) 条边的无向图,每条有边权 \(w_i\) ,现在要选择至多两条边断开,使得 \(S, T\) 不连通,并且使得边权和尽量小。
\(n \le 1000, m \le 30000\)
题解
我们分要选的边数进行考虑。
- \(0\) 条边:一开始 \(S,T\) 不连通直接判掉即可。
- \(1\) 条边:我们发现数据较小,可以暴力做。首先这条边必定存在于 \(S,T\) 在
Dfs
树的路径上,一开始先 Dfs 求出路径,然后依次枚举每条边断开,再用Dfs
判是否连通就行了,最后把边权取个 \(\min\) 就行了。复杂度是 \(O(n(n+m))\) 。 - \(2\) 条边:可以和上面的思路一样做,因为其中一条边也是存在于之前那条路径上的。然后我们依旧是暴力枚举第一条路径。然后我们再断开那条边,再求出
Dfs
树,然后用Tarjan
求出桥边就行了,然后依次判断这些树边是否为桥边。如果是,那么就是一个合法解,最后把答案和这两条边权和取 \(\min\) 。复杂度也是 \(O(n(n+m))\) 的。
总结
对于一类 \(n, m\) 范围不同的题,如果要暴力枚举每一条边,可以找找这条边是否有什么性质,常常可以将枚举边的条数从 \(O(m)\) 降到 \(O(n)\) 。
代码
这里需要注意实现细节。比如 Dfs
求 \(S \to T\) 路径,我们可以不要求 \(Lca\) ,可以从 \(S\) Dfs
的时候,记下这条路径是否到达了 \(T\) ,因为是树所以路径唯一。
然后会有重边的情况,我们可以第一次枚举到 \(u\) 点的父亲时候跳过,后面都需要更新 lowlink
就行了。
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
using namespace std;
typedef pair<int, int> PII;
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
}
void File() {
#ifdef zjp_shadow
freopen ("F.in", "r", stdin);
freopen ("F.out", "w", stdout);
#endif
}
const int N = 1010, M = 30100 << 1, inf = 0x7f7f7f7f;
int Head[N], Next[M], to[M], val[M], e = 1;
inline void add_edge(int u, int v) { to[++ e] = v; Next[e] = Head[u]; Head[u] = e; }
inline void Add(int u, int v) { add_edge(u, v); add_edge(v, u); }
#define Travel(i, u, v) for(int i = Head[u], v = to[i]; i; v = to[i = Next[i]])
int S, T;
vector<int> V, G; bitset<N> vis; bitset<M> ban;
bool Dfs(int u) {
vis[u] = true; if (u == T) return true;
Travel(i, u, v) if (!ban[i] && !vis[v] && Dfs(v))
return V.push_back(i), true;
return false;
}
int clk, dfn[N], lowlink[N]; bitset<M> Bridge;
void Tarjan(int u, int fa = 0) {
dfn[u] = lowlink[u] = ++ clk;
bool fir = true;
Travel(i, u, v) if (!ban[i]) {
if (v == fa && fir) { fir = false; continue ; }
if (!dfn[v]) {
Tarjan(v, u);
chkmin(lowlink[u], lowlink[v]);
if (lowlink[v] > dfn[u]) Bridge[i] = Bridge[i ^ 1] = true;
} else chkmin(lowlink[u], dfn[v]);
}
}
PII Ans;
int main () {
File();
int n = read(), m = read(); S = read(); T = read();
For (i, 1, m) {
int u = read(), v = read(), w = read();
Add(u, v); val[e] = val[e ^ 1] = w;
}
if (!Dfs(S)) return puts("0\n0"), 0; G.swap(V);
int ans = inf;
for (int cur : G) {
ban[cur] = ban[cur ^ 1] = true; vis.reset();
if (!Dfs(S)) {
if (chkmin(ans, val[cur])) Ans = mp(cur >> 1, 0);
ban[cur] = ban[cur ^ 1] = false; continue ;
}
clk = 0; Bridge.reset(); Set(dfn, 0);
For (i, 1, n) if (!dfn[i]) Tarjan(i, 0);
for (int cut : V)
if (Bridge[cut] && chkmin(ans, val[cur] + val[cut])) Ans = mp(cur >> 1, cut >> 1);
V.clear(); ban[cur] = ban[cur ^ 1] = false;
}
if (ans == inf) return puts("-1"), 0;
printf ("%d\n", ans);
if (!Ans.second) printf ("1\n%d\n", Ans.first);
else printf ("2\n%d %d\n", Ans.first, Ans.second);
return 0;
}
Codeforces 700 C. Break Up(Tarjan求桥)的更多相关文章
- Tarjan求桥
传送门(poj3177) 这道题是Tarjan求桥的模板题.大意是要求在原图上加上数量最少的边,使得整张图成为一个边双联通分量. 具体的做法是,先在图中求出所有的桥,之后把边双联通分量缩成点,这样的话 ...
- Tarjan 求桥,割,强连通
最近遇到了这种模板题,记录一下 tarjan求桥,求割 #include <bits/stdc++.h> using namespace std; #define MOD 99824435 ...
- hdu 4738 Caocao's Bridges (tarjan求桥)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4738 题目大意:给一些点,用一些边把这些点相连,每一条边上有一个权值.现在要你破坏任意一个边(要付出相 ...
- tarjan求桥、割顶
若low[v]>dfn[u],则(u,v)为割边.但是实际处理时我们并不这样判断,因为有的图上可能有重边,这样不好处理.我们记录每条边的标号(一条无向边拆成的两条有向边标号相同),记录每个点的父 ...
- UVA 796 Critical Links(Tarjan求桥)
题目是PDF就没截图了 这题似乎没有重边,若有重边的话这两点任意一条边都不是桥,跟求割点类似的原理 代码: #include <stdio.h> #include <bits/std ...
- Codeforces 160D Edges in MST tarjan找桥
Edges in MST 在用克鲁斯卡尔求MST的时候, 每个权值的边分为一类, 然后将每类的图建出来, 那些桥就是必须有的, 不是桥就不是必须有. #include<bits/stdc++.h ...
- UVA796 - Critical Links(Tarjan求桥)
In a computer network a link L, which interconnects two servers, is considered critical if there are ...
- poj3694(lca + tarjan求桥模板)
题目链接: http://poj.org/problem?id=3694 题意: 给出一个 n 个节点 m 条边的图, 然后有 q 组形如 x, y 的询问, 在前面的基础上连接边 x, y, 输出当 ...
- HDU-4612 Warm up,tarjan求桥缩点再求树的直径!注意重边
Warm up 虽然网上题解这么多,感觉写下来并不是跟别人竞争访问量的,而是证明自己从前努力过,以后回头复习参考! 题意:n个点由m条无向边连接,求加一条边后桥的最少数量. 思路:如标题,tarjan ...
随机推荐
- 助教总结 -【福大软工实践-2017-2018-K班】
助教总结 -[福大软工实践-2017-2018-K班] 非常抱歉这么晚才来写总结! 助教工作 助教共发表博客39篇. 助教共点评约500条. 起步 对于常规课程的起步,通常都是在第一次课堂上由老师对课 ...
- 容器化 — 基于Docker技术容器云
导读:本文介绍了基于Docker技术的企业级应用容器平台,从云的定义.云服务分类,到用友云PaaS基础平台.平台总体架构.架构预览.部署架构.平台核心价值和核心竞争力,阐述PaaS基础平台成为广大传统 ...
- Oracle和Elasticsearch数据同步
Python编写Oracle和Elasticsearch数据同步脚本 标签: elasticsearchoraclecx_Oraclepython数据同步 Python知识库 一.版本 Pyth ...
- 学习memcache
本文参考了菜鸟教程中的内容. 安装 安装memcache的时候,请切换为root用户 root@centos # wget http://www.memcached.org/files/memcach ...
- Spring Mvc和Spring Boot读取Profile方式
spring boot java代码中获取spring.profiles.active - u013042707的专栏 - CSDN博客https://blog.csdn.net/u013042707 ...
- asp.net Json序列化
Json作为一种数据传输格式与标准被广泛的使用在项目开发中,可以说简直离不开它.那么怎么来生成JSON格式的数据就成了我们首先需要解决的问题这里我们使用.net. 首先是获取数据 public ban ...
- JavaScript生成二维码图片
1.引入一个二维码工具的js文件,同时需要引入jquery文件 下面是jquery.qrcode.min.js文件内容: (function(r){r.fn.qrcode=function(h){va ...
- IdentityServer4【QuickStart】之设置和概述
设置和概述 有两个基本的方式来开启一个新的IdentityServer项目: 从头开始 从asp.net Identity模板开始 如果你从头开始,我们提供了一些基于内存中构建的存储,所以你不必一开始 ...
- java 浅拷贝和深拷贝 对象克隆clone
分一下几点讨论: 为什么要克隆? 如何实现克隆 浅克隆和深克隆 解决多层克隆问题 总结 一:为什么要克隆? 大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗? 答案是:克隆的对象可能包 ...
- 腾讯机试题 AcWing 603 打怪兽
题目链接:https://www.acwing.com/problem/content/605/ 题目大意: 略 分析: 用dp[i][j]表示用j元钱能在前i只怪兽上所能贿赂到的最大武力值. 有一种 ...