hdu4005 缩点+无向图+重边

奉上数据:

6 7
1 2 1
2 1 1
2 3 1
3 4 1
4 3 1
1 6 2
4 5 3






5 8
1 2 1
2 1 1
2 3 2
3 2 2
3 4 3
4 3 3
4 5 4
5 4 4


1 0


7 7
1 2 1
2 4 2
3 4 1
4 3 1
3 5 2
3 6 3
6 7 3



缩点后的树边中,找出最小的边,从最小边的两端点出发,分别含有两个子树中的最小边的路径上,这些边排除掉,剩下的边里面最大的就是答案


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;
#define N 10500
#define M 200500
#define INF 100000000
int n,m,ans;
struct Edge
{
	int v,w;
	Edge()
	{v=0;w=0;}
	Edge(int _v,int _w)
	{v=_v;w=_w;}
}edge[M];
int head[N],adj[M],e;
int dfn[N],low[N],cnt;
int sta[N],sum,top,scc[N];
vector<Edge>vec[N];
void  dfs(int u,int preedge) // preedge 解决重边
{
	dfn[u]=low[u]=++cnt;
	sta[top++]=u;
	for(int i=head[u];i!=-1;i=adj[i])
	{
		int v=edge[i].v;
		if(dfn[v]==0)
		{
			dfs(v,i);
			low[u]=min(low[u],low[v]);
		}
 		else if((i^1)==preedge) 
			continue;
		else 
			low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		int i;
        ++sum;
		do
		{
			i=sta[--top];
			scc[i]=sum;
		}while(i!=u);
	}
}
void insert(int u,int v,int w)
{
	edge[e].v=v;edge[e].w=w;
	adj[e]=head[u];head[u]=e++;
	edge[e].v=u;edge[e].w=w;
	adj[e]=head[v];head[v]=e++;
}
void init()
{
	memset(head,-1,sizeof(head));
	e=0;cnt=sum=top=0;
	for(int i=0;i<=n+5;++i)
		dfn[i]=low[i]=scc[i]=0;
}

//缩点后形成一颗树,敌人的策略是在树上加条边产生个环,这个环我放无法破坏其连通性
//为了让我方付出更大的代价敌人一定把权值小的边放在环上,
//最坏的情况是第一小和第二小的边都在环上
//找出第一小的边,以两端点为起点dfs,每次在一个节点,都找出含有最小权边的子树,开下去
//取第二小的边更新ans

int dfs2(int u,int fa)
{
	int m1=INF,m2=INF,v,temp,w;
	for(int i=0;i<vec[u].size();++i)
	{
		v=vec[u][i].v;
		if(v==fa)
			continue;
		w=vec[u][i].w;
		if(w<m2)
			m2=w;
		temp=dfs2(v,u);
		if(temp<m2)
			m2=temp;
		if(m2<m1)
			swap(m1,m2);
	}
	if(m2<ans)
		ans=m2;
	return m1;
}
int main ()
{
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		int u,v,w;
		init();
		for(int i=1;i<=m;++i)
		{
			scanf("%d%d%d",&u,&v,&w);
			insert(u,v,w);
		}
		for(int i=1;i<=n;++i)
			if(!dfn[i])
				dfs(i,-1);
		for(int i=0;i<=sum;++i)
			vec[i].clear();
		int min_edge,st=-1,ed=-1;
		min_edge=INF;
		for(u=1;u<=n;++u)
			for(int i=head[u];i!=-1;i=adj[i])
				if(scc[u]!=scc[edge[i].v])
				{
					vec[scc[u]].push_back(Edge(scc[edge[i].v],edge[i].w));
					if(min_edge>edge[i].w)
						min_edge=edge[i].w,st=scc[u],ed=scc[edge[i].v];
				}
		ans=INF;
		if(st==-1||ed==-1)
		{
			printf("-1\n");
			continue;
		}
		dfs2(st,ed);
		dfs2(ed,st);
	
		if(ans>=INF)
			printf("-1\n");
		else 
			printf("%d\n",ans);
	}
	//system("pause");
	return 0;
}






你可能感兴趣的:(hdu4005 缩点+无向图+重边)