题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4005
题意:给出一个带权无向图。权表示删除该边的代价。现在会新增加一条边之后你可以删除一条边使得图不连通。求最小代价。
思路:首先将图缩点变成树。之后找到树中最小的边(u,v),然后从u,v分别向下DFS,到达一个点S时,S下面的边的次小值可以更新答案。
vector<pair<int,int> > V1[N];
int dfn[N],low[N],visit[N],color[N];
int id,n,m,colorCnt;
stack<int> S;
struct node
{
int v,w,next;
};
node edges[200005];
int head[N];
int e;
void add(int u,int v,int w)
{
edges[e].v=v;
edges[e].w=w;
edges[e].next=head[u];
head[u]=e++;
}
void DFS(int u,int pre,int preEdgeId)
{
low[u]=dfn[u]=++id;
S.push(u);
visit[u]=1;
int i;
for(i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].v;
if(v==pre&&(i^1)==preEdgeId) continue;
if(!dfn[v])
{
DFS(v,u,i);
upMin(low[u],low[v]);
}
else if(visit[v])
{
upMin(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
colorCnt++;
int v;
do
{
v=S.top();
S.pop();
visit[v]=0;
color[v]=colorCnt;
}while(u!=v);
}
}
int MinEdge,MinEdgeA,MinEdgeB;
void reBuild()
{
MinEdge=INF;
int i;
FOR1(i,colorCnt) V1[i].clear();
FOR1(i,n)
{
int j;
for(j=head[i];j!=-1;j=edges[j].next)
{
int v=edges[j].v;
int w=edges[j].w;
if(color[i]!=color[v])
{
V1[color[i]].pb(MP(color[v],w));
if(w<MinEdge)
{
MinEdge=w;
MinEdgeA=color[i];
MinEdgeB=color[v];
}
}
}
}
}
void deal()
{
while(!S.empty()) S.pop();
clr(visit,0);
clr(dfn,0);
int i;
id=colorCnt=0;
FOR1(i,n) if(!dfn[i]) DFS(i,-1,-1);
reBuild();
}
int ans;
int dfs(int u,int pre)
{
int i;
int Min1=-1,Min2=-1,Min=INF;
FOR0(i,SZ(V1[u]))
{
int v=V1[u][i].first;
int w=V1[u][i].second;
if(v==pre) continue;
int MM=dfs(v,u);
if(MM<w) w=MM;
if(-1==Min1) Min1=w;
else if(-1==Min2)
{
if(w<Min1) Min2=Min1,Min1=w;
else Min2=w;
}
else
{
if(w<Min1) Min2=Min1,Min1=w;
else if(w<Min2) Min2=w;
}
if(w<Min) Min=w;
}
if(-1!=Min2) upMin(ans,Min2);
return Min;
}
int main()
{
Rush(n)
{
RD(m);
int i;
FOR1(i,n) head[i]=-1;
e=0;
FOR1(i,m)
{
int u,v,w;
RD(u,v,w);
add(u,v,w);
add(v,u,w);
}
deal();
ans=INF;
dfs(MinEdgeA,MinEdgeB);
dfs(MinEdgeB,MinEdgeA);
if(INF==ans) puts("-1");
else PR(ans);
}
}