HDU 4005 The war(双连通好题)

HDU 4005 The war

题目链接

题意:给一个连通的无向图,每条边有一个炸掉的代价,现在要建一条边(你不不知道的),然后你要求一个你需要的最少代价,保证不管他建在哪,你都能炸掉使得图不连通

思路:炸肯定要炸桥,所以先双连通缩点,得到一棵树,树边是要炸的,那么找一个最小值的边,从该边的两点出发,走的路径中,把两条包含最小值的路径,的两点连边,形成一个环,这个环就保证了最低代价在里面,除了这个环以外的最小边,就是答案,这样的话,就利用一个dfs,搜到每个子树的时候进行一个维护即可

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 10005;
const int M = 200005;

int n, m;

struct Edge {
	int u, v, val, id;
	bool iscut;
	Edge() {}
	Edge(int u, int v, int val, int id) {
		this->u = u;
		this->v = v;
		this->val = val;
		this->id = id;
		this->iscut = false;
	}
} edge[M];

int en, first[N], next[M];

void init() {
	en = 0;
	memset(first, -1, sizeof(first));
}

void add_edge(int u, int v, int val, int id) {
	edge[en] = Edge(u, v, val, id);
	next[en] = first[u];
	first[u] = en++;
}

int pre[N], dfn[N], dfs_clock, bccn, bccno[N];
vector<Edge> bcc[N];

void dfs_cut(int u, int id) {
	pre[u] = dfn[u] = ++dfs_clock;
	for (int i = first[u]; i + 1; i = next[i]) {
		if (edge[i].id == id) continue;
		int v = edge[i].v;
		if (!pre[v]) {
			dfs_cut(v, edge[i].id);
			dfn[u] = min(dfn[u], dfn[v]);
			if (dfn[v] > pre[u])
				edge[i].iscut = edge[i^1].iscut = true;
		} else dfn[u] = min(dfn[u], pre[v]);
	}
}

void find_cut() {
	dfs_clock = 0;
	memset(pre, 0, sizeof(pre));
	for (int i = 1; i <= n; i++)
		if (!pre[i]) dfs_cut(i, -1);
}

void dfs_bcc(int u) {
	bccno[u] = bccn;
	for (int i = first[u]; i + 1; i = next[i]) {
		if (edge[i].iscut) continue;
		int v = edge[i].v;
		if (bccno[v]) continue;
		dfs_bcc(v);
	}
}

const int INF = 0x3f3f3f3f;

Edge Mine;

void find_bcc() {
	bccn = 0;
	memset(bccno, 0, sizeof(bccno));
	for (int i = 1; i <= n; i++) {
		if (!bccno[i]) {
			bccn++;
			dfs_bcc(i);
		}
	}
	for (int i = 1; i <= bccn; i++) bcc[i].clear();
	Mine.val = INF;
	for (int i = 0; i < en; i++) {
		if (!edge[i].iscut) continue;
		if (Mine.val > edge[i].val)
			Mine = edge[i];
		int u = bccno[edge[i].u], v = bccno[edge[i].v], w = edge[i].val;
		bcc[u].push_back(Edge(u, v, w, 0));
	}
}

int ans;

int dfs(int u, int f) {
	int Min1 = INF, Min2 = INF;
	for (int i = 0; i < bcc[u].size(); i++) {
		int v = bcc[u][i].v;
		if (v == f) continue;
		Min2 = min(min(dfs(v, u), bcc[u][i].val), Min2);
		if (Min2 < Min1) swap(Min1, Min2);
	}
	ans = min(ans, Min2);
	return Min1;
}

int main() {
	while (~scanf("%d%d", &n, &m)) {
		init();
		int u, v, w;
		for (int i = 0; i < m; i++) {
			scanf("%d%d%d", &u, &v, &w);
			if (u > n || v > n) continue;
			add_edge(u, v, w, i);
			add_edge(v, u, w, i);
		}
		find_cut();
		find_bcc();
		if (bccn == 1) {
			printf("-1\n");
			continue;
		}
		ans = INF;
		u = bccno[Mine.u]; v = bccno[Mine.v];
		dfs(u, v);
		dfs(v, u);
		if (ans == INF) ans = -1;
		printf("%d\n", ans);
	}
	return 0;
}
时间: 2024-12-28 05:58:49

HDU 4005 The war(双连通好题)的相关文章

hdu 4612 Warm up 双连通缩点+树的直径

首先双连通缩点建立新图(顺带求原图的总的桥数,其实由于原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首尾,这样就将原图的桥减少了直径个. #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> #include<map&g

ZOJ 2588 Burning Bridges 求无向图桥 边双连通裸题

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1588 binshen的板子: #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #i

HDU 2460 Network(双连通+树链剖分+线段树)

HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链剖分+线段树处理 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #pragma comment(linke

Railway HDU - 3394 (点双连通)

Railway HDU - 3394 题意:一个无向图,1求不在任何一个环里的边数:2求在不止一个环里的边数. 第一问明显就是求桥,第二问,如果求出的某个点双连通分量里面边数多于点数,说明不止一个环,那么所有的边都在不止一个环里. 该求点双连通的,,求成了边双连通...要仔细分析问题. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 us

hdu 2242 考研路茫茫――空调教室 (双连通入门题)

1 /********************************************************** 2 题目: 考研路茫茫——空调教室(hdu 2242) 3 链接: http://acm.hdu.edu.cn/showproblem.php?pid=2242 4 算法: 双联通 5 思路: 找到桥,然后计算桥两边的差,在把桥一边 6 的值压缩到和另一边相邻的数上. 7 8 *************************************************

hdu 4005 The war

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4005 In the war, the intelligence about the enemy is very important. Now, our troop has mastered the situation of the enemy's war zones, and known that these war zones can communicate to each other direc

HDU 4005 The war Tarjan+dp

The war Problem Description In the war, the intelligence about the enemy is very important. Now, our troop has mastered the situation of the enemy's war zones, and known that these war zones can communicate to each other directly or indirectly throug

【图论】双连通总结

双连通总结 这类问题分为,边-双连通,点-双连通 边双连通 边双连通,求出来后,连接没一个双连通的分量的就是割边,因此可以缩点成一棵树,把问题转化为在树上搞,割边的定义为:去掉这条边后图将不连通 基本这类题都一个解法,求双连通分量,然后缩点成树,进行操作 或者就是直接要求割边,做跟割边相关的操作 模板: #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #

HDU 3849 By Recognizing These Guys, We Find Social Networks Useful(双连通)

HDU 3849 By Recognizing These Guys, We Find Social Networks Useful 题目链接 题意:说白了就是求一个无向图的桥 思路:字符串hash掉,然后双连通.要注意特判一下假设不是一个连通块.那么答案是0 代码: #include <cstdio> #include <cstring> #include <string> #include <vector> #include <map> us