Hdu4005-The war(双连通缩点)

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 through the network. We also know the enemy is going to build a new communication line to strengthen their communication network. Our task is to destroy their communication network, so that some of their war zones can't communicate. Each line has its "cost of destroy". If we want to destroy a line, we must spend the "cost of destroy" of this line. We want to finish this task using the least cost, but our enemy is very clever. Now, we know the network they have already built, but we know nothing about the new line which our enemy is going to build. In this condition, your task is to find the minimum cost that no matter where our enemy builds the new line, you can destroy it using the fixed money. Please give the minimum cost. For efficiency, we can only destroy one communication line.

Input

The input contains several cases. For each cases, the first line contains two positive integers n, m (1<=n<=10000, 0<=m<=100000) standing for the number of the enemy's war zones (numbered from 1 to n), and the number of lines that our enemy has already build. Then m lines follow. For each line there are three positive integer a, b, c (1<=a, b<=n, 1<=c<=100000), meaning between war zone A and war zone B there is a communication line with the "cost of destroy " c.

Output

For each case, if the task can be finished output the minimum cost, or output ‐1.

Sample Input

3 2
1 2 1
2 3 2
4 3
1 2 1
1 3 2
1 4 3

Sample Output

-1
3

题意: 敌人在N个点间建了M条线路,每条线路都有一个权值,敌人要再建一条线路,己方可以毁掉敌方的一条线路,问己方最少要花多少钱(至少得准备多少钱)才能使

这些点不连通。

 

解析: 先分离出每个双连通分量(删除双联通分量中的任何一条边还是连通的,没有意义),给每个分量重新编一个号,缩成一个点,在Tarjan算法过程中把桥保存下来。

选一条权值最小的桥,分别从两头出发,找次小的桥。答案就是次小的桥的权值,为甚么是找次小的桥,因为如果敌人是把最小的桥所连的两个连通分量再加一条边,则

必须删次小的桥,如果是其他,则只需要删最小的桥即可。

 

代码

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<utility>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<iterator>
#include<stack>
using namespace std;
typedef __int64 LL;
const int INF=1e9+7;
const double eps=1e-7;
const int maxn=10005;
const int maxm=100005;
int N,M,eid,id,top;
int scc_id,scc[maxn],dfn[maxn],low[maxn],b[maxn],fa[maxn];
int head[maxn],KK[maxn];
struct edge
{
    int v,w,next;
    edge(int v=0,int w=0,int next=-1):v(v),w(w),next(next){}
}E[2*maxm];
struct node
{
    int u,v,w;
    node(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
};
vector<node> V;
void init()
{
    eid=id=top=scc_id=0;
    for(int i=0;i<=N;i++)
    {
        head[i]=-1;
        dfn[i]=low[i]=b[i]=scc[i]=0;
        fa[i]=i;
    }
    V.clear();
}
void AddEdge(int u,int v,int w)
{
    E[++eid]=edge(v,w,head[u]);
    head[u]=eid;
}
void Tarjan(int u)
{
    dfn[u]=low[u]=++id;
    KK[top++]=u;
    bool first=false;
    for(int i=head[u];i!=-1;i=E[i].next)
    {
        edge& e=E[i];
        int v=e.v,w=e.w;
        if(v==fa[u]&&!first){ first=true; continue; }
        if(!dfn[v])
        {
            fa[v]=u;
            Tarjan(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]) V.push_back(node(u,v,w));//这条边是桥
        }
        else low[u]=min(low[u],dfn[v]);
    }
    int t;
    if(dfn[u]==low[u])
    {
        scc_id++;  //双连通分量
        do
        {
            t=KK[--top];
            b[t]=scc_id; //连通分量编号
        }while(u!=t);
    }
    return;
}
int ans;
int FindPath(int u,int pre)
{
    int Min=INF,MMin=INF;
    for(int i=head[u];i!=-1;i=E[i].next)
    {
        int v=E[i].v,w=E[i].w;
        if(v==pre) continue;
        int t=FindPath(v,u);
        if(t<MMin) MMin=t;
        if(w<MMin) MMin=w;
        if(Min>MMin) swap(Min,MMin);
    }
    ans=min(ans,MMin);
    return Min;
}
int main()
{
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        init();
        int u,v,w;
        for(int i=1;i<=M;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            AddEdge(u,v,w); //建边
            AddEdge(v,u,w); //反向边
        }
        for(int i=1;i<=N;i++) if(!dfn[i]) Tarjan(i); //找连通分量

        int mindist=INF,picku,pickv,Size=V.size();
        eid=0;
        memset(head,-1,sizeof(head));
        for(int i=0;i<Size;i++) //重新建图
        {
            node& t=V[i];
            int u=t.u,v=t.v,w=t.w;
            AddEdge(b[u],b[v],w);
            AddEdge(b[v],b[u],w);
            if(w<mindist){ mindist=w,picku=b[u],pickv=b[v]; } //权值最小的桥
        }
        ans=INF;
        FindPath(picku,pickv);
        FindPath(pickv,picku);
        if(ans==INF) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2016-07-31 14:47  wust_ouyangli  阅读(204)  评论(0编辑  收藏  举报