hdu4005The war

思路:
无向图求连通分量。我们首先应该知道,因为加入的边未知,所以我们所求的最小金额就是无论加入的边在图中哪里,我们都可以删除一条边来使它不连通。so我们首先对图求解连通分量,然后缩点,形成一棵树。这时候,我们可以想到,在加入一条未知的边之后会形成一个环,显然最小值的边不是我们的答案,因为这条边有可能就在这个环中,这时候我们就删除不了边了(其他边的值都比这个值大)。
我们仔细想想可以发现:根据题意构造最优路径,一条路径通过以结点u为根的子树时,一定会经过以结点u为根的子树中边权最小的那条边,那么这时候我们除去这条路径后剩下的边权中的最小值就是我们要求的答案了。所以,我们的算法思想就是:递归求解每个结点为根的子树中的最小边和次小边,我们必须保证这里最小边和次小边不可能在一条路径上,然后求次小边中的最小值就是答案了。
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
// #define DEBUG
#ifdef DEBUG
#define debug(...) printf( __VA_ARGS__ )
#else
#define debug(...)
#endif
#define MEM(x,y) memset(x, y,sizeof x)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 10010;
const int maxm = 1000010;
int cnt, num;
int head[maxn], pnt[maxm], nxt[maxm], w[maxm];
bool vis[maxm], in[maxn];
int n, m;
int dfn[maxn], low[maxn], id[maxn];
int tol;
inline void Init(){
	cnt = num = tol = 0;
	MEM(in, false);
	MEM(head, -1);
	MEM(dfn, -1);
	MEM(low, -1);
	MEM(id, -1);
}
inline void add(int u,int v,int c){
	pnt[cnt] = v;nxt[cnt] = head[u];
	vis[cnt] = false;w[cnt] = c;head[u] = cnt++;

	pnt[cnt] = u;nxt[cnt] = head[v];
	vis[cnt] = false;w[cnt] = c;head[v] = cnt++;
}
int t;
stack<int> st;
int rec[maxm][3];
void Tarjan(int u,int fa){
	dfn[u] = low[u] = t++;
	st.push(u);
	in[u] = true;
	for (int i = head[u];i != -1;i = nxt[i]){
		int v = pnt[i];
		if (vis[i]) continue;
		vis[i] = vis[i ^ 1] = true;
		if (dfn[v] == -1){
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
			if (low[v] > dfn[u]){
				rec[++tol][0] = u;
				rec[tol][1] = v;
				rec[tol][2] = w[i];
			}
		}else if (low[u] > dfn[v]){
			low[u] = dfn[v];
		}
	}
	if (dfn[u] == low[u]){
		while(true){
			int v = st.top();
			st.pop();
			id[v] = num;
			if (v == u) break;
		}
		num++;
	}
}
vector<ii> G[maxn];
int ans;
int dfs(int u,int fa){
	int Min = INF, vice_Min = INF, rr = INF;
	for (int i = 0;i < G[u].size();++i){
		int v = G[u][i].first, cost = G[u][i].second;
		if (v == fa) continue;
		int now = dfs(v, u);
		if (now < vice_Min) vice_Min = now;
		if (cost < vice_Min) vice_Min = cost;
		if (Min > vice_Min) swap(vice_Min, Min);
		if (Min < rr) rr = Min;
	}
	if (ans > vice_Min) ans = vice_Min;
	return rr;
}
int main()
{	
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	while(~scanf("%d%d",&n, &m)){
		t = 0;
		Init();
		for (int i = 1, a, b, c;i <= m;++i){
			scanf("%d%d%d",&a, &b, &c);
			add(a, b, c);
		}
		for (int i = 1;i <= n;++i)
			if (dfn[i] == -1) Tarjan(i, -1);
		for (int i = 0;i <= n;++i)
			G[i].clear();
		int a, b, Min = INF;
		for (int i = 1;i <= tol;++i){
			int u = rec[i][0], v = rec[i][1], cost = rec[i][2];
			G[id[u]].push_back(ii(id[v], cost));
			G[id[v]].push_back(ii(id[u], cost));
			if (cost < Min){
				a = id[u],b = id[v];
				Min = cost;
			}
		}
		ans = INF;
		dfs(a, b);
		dfs(b, a);
		if (ans == INF) printf("-1\n");
		else printf("%d\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值