HDU 4005 The war 双连通分量 缩点
2016-04-07 10:06
381 查看
题意:
有一个边带权的无向图,敌人可以任意在图中加一条边,然后你可以选择删除任意一条边使得图不连通,费用为被删除的边的权值。求敌人在最优的情况下,使图不连通的最小费用。
分析:
首先求出边双连通分量,缩点成树。敌人如果选则树中\(u,v\)节点之间加一条边,则路径\(u \to v\)中所有的边都会变成环。
我们只能考虑删除其他的权值最小的边使图不连通。
从敌人的角度考虑:如果使树中权值最小的边成环,那么我们的费用会增加。在最小边成环的前提下,如果还能使次小边也成环,我们的费用又会增加,以此类推。
因此先找到最小边,然后从这条边两头DFS,肯定选择最小值所在的子树延长路径,然后用其他子树中的最小边更新答案。
#include <cstdio> #include <cstring> #include <algorithm> #include <stack> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 10000 + 10; const int maxm = 200000 + 10; struct Edge { int v, w, nxt; Edge() {} Edge(int v, int w, int nxt): v(v), w(w), nxt(nxt) {} }; struct Graph { int ecnt, head[maxn]; Edge edges[maxm]; void init() { ecnt = 0; memset(head, -1, sizeof(head)); } void AddEdge(int u, int v, int w) { edges[ecnt] = Edge(v, w, head[u]); head[u] = ecnt++; } }; Graph g, t; int n, m; stack<int> S; int dfs_clock, pre[maxn], low[maxn]; int scc_cnt, sccno[maxn]; void dfs(int u, int fa) { pre[u] = low[u] = ++dfs_clock; S.push(u); bool flag = false; for(int i = g.head[u]; ~i; i = g.edges[i].nxt) { int v = g.edges[i].v; if(v == fa && !flag) { flag = true; continue; } if(!pre[v]) { dfs(v, u); low[u] = min(low[u], low[v]); } else if(!sccno[v]) low[u] = min(low[u], pre[v]); } if(low[u] == pre[u]) { scc_cnt++; for(;;) { int x = S.top(); S.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } void find_scc() { memset(pre, 0, sizeof(pre)); memset(sccno, 0, sizeof(sccno)); dfs_clock = scc_cnt = 0; dfs(1, 0); } int ans; int dfs2(int u, int fa) { int min1 = INF, min2 = INF; for(int i = t.head[u]; ~i; i = t.edges[i].nxt) { int v = t.edges[i].v; if(v == fa) continue; int tmp = t.edges[i].w; tmp = min(tmp, dfs2(v, u)); if(tmp < min2) min2 = tmp; if(min2 < min1) swap(min1, min2); } ans = min(ans, min2); return min1; } int main() { while(scanf("%d%d", &n, &m) == 2) { g.init(); while(m--) { int u, v, w; scanf("%d%d%d", &u, &v, &w); g.AddEdge(u, v, w); g.AddEdge(v, u, w); } find_scc(); t.init(); int a, b, minEdge = INF; for(int u = 1; u <= n; u++) { for(int i = g.head[u]; ~i; i = g.edges[i].nxt) { int v = g.edges[i].v; if(sccno[u] == sccno[v]) continue; int w = g.edges[i].w; t.AddEdge(sccno[u], sccno[v], w); if(w < minEdge) { minEdge = w; a = sccno[u]; b = sccno[v]; } } } ans = INF; dfs2(a, b); dfs2(b, a); if(ans == INF) ans = -1; printf("%d\n", ans); } return 0; }
相关文章推荐
- UIWebView第三方进度条NJKWebViewProgress
- jvm参数设置 -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M
- 每天laravel-20160707|KeyWritten
- 干货技巧!有哪些实用秘诀可以帮助UI/UX设计师自我提升
- 视觉里程计总结
- 每天laravel-20160707|KeyWritten
- MongoDB3.0后的数据库安全认证
- 路径
- 闭包
- ECShop - 数据库操作类
- tinyint(4),tinyint(80)有什么区别
- 教你如何写thinkphp多表查询语句
- c语言学习----基本篇(上)
- Java连接SFTP服务器下载上传文件
- IOS 三维图像处理(九)--CATransform3D
- 浏览器、操作系统DNS缓存时间
- DAO初探
- mac 配置hadoop 2.6(单机和伪分布式)
- 作业四
- 5_1 大理石在哪儿(UVa10474)<排序与查找>