[kuangbin带你飞]专题九 连通图 题解+总结

kuangbin带你飞:点击进入新世界

总结:

本人算是初学者中的初学者,欢迎交流~
由于是个人总结向,所以有点精简,但是坑点和结果是怎么算出来的都会提及,当然如果有什么疑问可以留言或者私信交流。
后续会整理一下tarjan相关模板。

1.Network of Schools /强连通分量+缩点

原题链接:传送门

思路:

  1. 算是学完tarjan的第一发吧。
  2. tarjan求强连通分量,然后缩点,查看有几个强连通图,查看缩点后的DAG入度为0和出度为0的多少,选取其中最大值。
  3. 新的一条线为入度为0的连到出度为0,所以取max 。

    代码如下:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<iostream>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=5e5+5;
const int mamx=5e5+5;
// dfn 时间戳 low回溯 vis 是否在栈中
// ans为强连通分量里面的点数
// out 出度 in 入度
// s栈  col强连通
// cnt 强连通分量计数
ll head[manx],dfn[manx],low[manx],ans[manx];
ll out[manx],col[manx],s[manx],in[manx];
bool vis[manx];
ll k=0,ti=0,top=0,cnt=0,n,m;
struct node {
    ll v,next;
}e[mamx*2];
void add(ll u,ll v){
    e[++k].v=v;
    e[k].next=head[u];
    head[u]=k;
}
void tarjan(ll x){
    dfn[x]=low[x]=++ti,vis[x]=1,s[++top]=x;
    for(int i=head[x];i;i=e[i].next){
        ll u=e[i].v;
        if(!dfn[u]) tarjan(u),low[x]=min(low[x],low[u]);
        else if(vis[u]) low[x]=min(low[x],dfn[u]);
    }
    if(low[x]==dfn[x]){
        ++cnt;
        ll y;
        do{
            y=s[top--],vis[y]=0;
            col[y]=cnt;
            ans[cnt]++;
        }while(x!=y);
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        ll v=read();
        while(v){
            add(i,v);
            v=read();
        }
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=e[j].next)
            if(col[e[j].v]!=col[i])
                ++out[col[i]],++in[col[e[j].v]];
    ll res1=0,res2=0;
    for(int i=1;i<=cnt;i++){
        if(!out[i])
            res1++;
        if(!in[i])
            res2++;
    }
  //  cout<<res1<<" "<<res2<<endl;
    if(cnt==1) cout<<1<<endl<<0<<endl;
    else cout<<res2<<endl<<max(res1,res2)<<endl;
    return 0;
}


2.Network /割点模板题

原题链接:传送门

思路:

  1. tarjan求割点模板题。
  2. 割点的条件有:
  3. 对于根节点:有2棵即以上的子树
  4. 对于非根节点:low[v]>=dfn[u]

    代码如下:
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<iostream>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=5e5+5;
const int mamx=5e5+5;

ll head[manx],dfn[manx],low[manx];
bool vis[manx];
ll n,m,id,cnt,tot,k;
struct node {
    ll v,next;
}e[mamx*2];
void init(){
    memset(vis,0,sizeof(vis));
    memset(head,0,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    id=cnt=tot=k=0;
}
void add(ll u,ll v){
    e[++k].v=v;
    e[k].next=head[u];
    head[u]=k;
}
void tarjan(ll u,ll f){
    dfn[u]=low[u]=++id;
    int child=0;
    for(int i=head[u];i;i=e[i].next){
        ll v=e[i].v;
        if(!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]&&u!=f) vis[u]=1;
            if(u==f) child++;
        }
        low[u]=min(low[u],dfn[v]);
    }
    if(child>=2&&u==f) vis[u]=1; //如果是根节点,并且有一个以上的子节点
}
int main()
{
    int n,u,v;
    char c;
    while(scanf("%d",&n),n){
        init();
        while(scanf("%d",&u),u){
            while(scanf("%d%c",&v,&c)){
                add(u,v),add(v,u);
                if(c=='\n') break;
            }
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i,i);
        for(int i=1;i<=n;i++)
            if(vis[i])
                tot++;
        cout<<tot<<endl;
    }
    return 0;
}


3.Critical Links /桥的模板题

原题链接:传送门

思路:

  1. Tarjan求桥的模板题。
  2. 这题有要求按字典序输出,所以可以用vector + pair 来储存。
  3. pair的排序是先排序first后排序second。

    代码如下:
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm>
#include<iostream>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e3+5;
const int mamx=2e6+5;
/*
8
0 (1) 1
1 (3) 2 0 3
2 (2) 1 3
3 (3) 1 2 4
4 (1) 3
7 (1) 6
6 (1) 7
5 (0)
*/
ll head[manx],dfn[manx],low[manx];
ll bridge;
ll n,m,id,cnt,tot,k=1;
struct node {
    ll v,next;
    bool cut;
}a[mamx*2];
void init(){
    memset(head,0,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    id=cnt=tot=k=bridge=0;
}
void add(ll u,ll v){
    a[k].v=v;
    a[k].next=head[u];
    a[k].cut=false;
    head[u]=k++;
}
void tarjan(ll u,ll pre){
    dfn[u]=low[u]=++id;
    for(int i=head[u];i;i=a[i].next){
        ll v=a[i].v;
        if(v==pre) continue;
        if(!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]) a[i].cut=a[i^1].cut=1,bridge++;
        }
        else  low[u]=min(low[u],dfn[v]);
    }
}
int main()
{
    int n,m,u,v;
    char c;
    while(scanf("%d",&n)!=EOF){
        init();
        for(int i=1;i<=n;i++){
            scanf("%d%c%c%d%c",&u,&c,&c,&m,&c);
            for(int j=1;j<=m;j++) v=read(),add(u,v),add(v,u);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i,i);
        vector<pair<ll,ll> >ans;
        for(int i=0;i<k;i+=2){
            if(a[i].cut)
                if(a[i].v<a[i^1].v) ans.pb(mp(a[i].v,a[i^1].v));
                else ans.pb(mp(a[i^1].v,a[i].v));
        }
        sort(all(ans));
        cout<<ans.size()<<" critical links"<<endl;
        for(int i=0;i<ans.size();i++){
            cout<<ans[i].fi<<" - "<<ans[i].se<<endl;
        }
        cout<<endl;
    }
    return 0;
}


4.Network /桥+LCA

原题链接:传送门

思路:

  1. Tarjan求桥,然后利用lca思想,不断地更新答案。
  2. 因为当(u,v)相连时,u-v-lca(u,v) 构成了一个环,在这个环上的桥的属性取消。

    代码如下:
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm>
#include<iostream>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e5+5;
const int mamx=2e6+5;

ll head[manx],dfn[manx],low[manx];
ll bridge[manx],f[manx],d[manx],ans;
ll n,m,id,cnt,tot,k;
struct node {
    ll v,next;
}a[mamx*2];
void init(){
    memset(head,0,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(f,0,sizeof(f));
    memset(bridge,0,sizeof(bridge));
    memset(d,0,sizeof(d));
    id=cnt=tot=k=ans=0;
}
void add(ll u,ll v){
    a[k].v=v;
    a[k].next=head[u];
    head[u]=k++;
}
void tarjan(ll u,ll pre){
    dfn[u]=low[u]=++id;
    for(int i=head[u];i;i=a[i].next){
        ll v=a[i].v;
        if(v==pre) continue;
        if(!dfn[v]){
            f[v]=u;
            d[v]=d[u]+1;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]) bridge[v]=1,ans++;
        }
        else  low[u]=min(low[u],dfn[v]);
    }
}
void check(int u,int v){
    while(d[u]>d[v]){
        if(bridge[u]) ans--,bridge[u]=0;
        u=f[u];
    }
    while(d[v]>d[u]){
        if(bridge[v]) ans--,bridge[v]=0;
        v=f[v];
    }
    while(u!=v){
        if(bridge[v]) ans--,bridge[v]=0;
        if(bridge[u]) ans--,bridge[u]=0;
        u=f[u],v=f[v];
    }
}
int main()
{
    int n,m,u,v,t=1;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(!n&&!m) break;
        init();
        for(int i=1;i<=m;i++){
            u=read(),v=read();
            add(u,v),add(v,u);
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            if(!dfn[i]) tarjan(i,i);
        printf("Case %d:\n",t++);
        for(int i=1;i<=m;i++){
            u=read(),v=read();
            check(u,v);
            printf("%lld\n",ans);
        }
        printf("\n");
    }
    return 0;
}


5.Redundant Paths /双连通分量

原题链接:传送门

思路:

  1. tarjan算法求双连通分量(其实跟强连通分量是一样的)。
  2. 缩点形成一棵树,求这颗树有多少个叶子节点即可。
  3. 答案就是(叶子节点+1)/2。注意重边处理。
  4. 所有度为1的叶子结点两两相连 。

    代码如下:
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm>
#include<iostream>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e5+5;
const int mamx=2e6+5;

ll low[manx],dfn[manx],ssc[manx],s[manx],vis[manx],head[manx];
ll k,cnt,tot,top,id;
ll x[manx],y[manx],d[manx];
struct node{
    ll v,next;
    bool cut;
}a[mamx];
void init(){
    memset(vis,0,sizeof(vis));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(ssc,0,sizeof(ssc));
    memset(head,-1,sizeof(head));
    memset(s,0,sizeof(s));
    memset(d,0,sizeof(d));
    top=tot=cnt=k=id=0;
}
void add(int u,int v){
    a[k].next=head[u];
    a[k].v=v;
    a[k].cut=false;
    head[u]=k++;
}
void tarjan(int u,int pre){
    low[u]=dfn[u]=++id,vis[u]=1,s[++top]=u;
    for(int i=head[u];i!=-1;i=a[i].next){
        int v=a[i].v;
        if(v==pre) continue;
        if(!dfn[v]){
            tarjan(v,u),low[u]=min(low[u],low[v]);
            if(dfn[u]<low[v]) a[i].cut=a[i^1].cut=1;
        }
        else if(vis[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        int v;
        cnt++;
        do{
            v=s[top--],vis[v]=0;
            ssc[v]=cnt;
        }while(v!=u);
    }
}
int main()
{
    int n,m,u,v;
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        for(int i=1;i<=m;i++){
            x[i]=read(),y[i]=read();
            u=x[i],v=y[i];
            add(u,v),add(v,u);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i,i);
        for(int i=0;i<k;i++){
            if(a[i].cut)
                d[ssc[a[i].v]]++;
        }
        ll ans=0;
        for(int i=1;i<=cnt;i++)
            if(d[i]==1) ans++;
     //   cout<<ans<<endl;
        printf("%lld\n",(ans+1)/2);
    }
    return 0;
}


6.Strongly connected /强通块+缩点

原题链接:传送门

思路:

  1. 找出强联通块,计算每个连通块内的个数。
  2. 将点数最少的那个连通块单独拿出来作为连通分量a,其余的连通块合并成一个连通分量。
  3. 要使其为强连通图,那边数为n*(n-1)-m-a*(n-a)
  4. 原本的边数为m 能添加多少边 取决于 -a*n+a^2
  5. 由于n比a大,所以a越小能添加的边数越多,所以取缩点后的连通块里面块数最小的为a 。

代码如下:

//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm>
#include<iostream>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e5+5;
const int mamx=2e6+5;

ll low[manx],dfn[manx],ssc[manx],s[manx],vis[manx],head[manx];
ll x[manx],y[manx],in[manx],out[manx],cnts[manx];
ll k,cnt,tot,top,id;
struct node{
    ll v,next;
}a[mamx];
void init(){
    memset(vis,0,sizeof(vis));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(ssc,0,sizeof(ssc));
    memset(head,-1,sizeof(head));
    memset(cnts,0,sizeof(cnts));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(s,0,sizeof(s));
    top=tot=cnt=k=id=0;
}
void add(int u,int v){
    a[k].next=head[u];
    a[k].v=v;
    head[u]=k++;
}
void tarjan(int u){
    low[u]=dfn[u]=++id,vis[u]=1,s[++top]=u;
    for(int i=head[u];i!=-1;i=a[i].next){
        int v=a[i].v;
        if(!dfn[v])
            tarjan(v),low[u]=min(low[u],low[v]);
        else if(vis[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        int v;
        cnt++;
        do{
            v=s[top--],vis[v]=0;
            ssc[v]=cnt;
            cnts[cnt]++;
        }while(v!=u);
    }
}
int main()
{
    ll p=read(),u,v,t=1;
    while(p--){
        ll n=read(),m=read();
        init();
        for(int i=1;i<=m;i++){
            u=x[i]=read(),v=y[i]=read();
            add(u,v);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i);
        if(cnt==1){
            printf("Case %d: -1\n",t++);
            continue;
        }
        for(int i=1;i<=m;i++){
            u=ssc[x[i]],v=ssc[y[i]];
            if(u!=v)
                out[u]++,in[v]++;
        }
        ll ans=n*(n-1)-m,mi=n;
        for(int i=1;i<=cnt;i++)
            if(!in[i]||!out[i])
                mi=min(mi,cnts[i]);
        printf("Case %d: ",t++);
        cout<<ans-mi*(n-mi)<<endl;
    }
    return 0;
}


7.Caocao’s Bridges /桥

原题链接:传送门

思路:

  1. 注意重边处理。
  2. 守卫为0时,也需要派一个人;
  3. 如果原本图不连通,就不需要派人。
  4. 然后直接输出桥的最小边权就可以了。

    代码如下:
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm>
#include<iostream>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;

const int manx=1e3+5;
const int mamx=2e6+5;

ll low[manx],dfn[manx],head[manx];
ll k,cnt,top,id,bridge;
struct node{
    ll v,next,w;
}a[mamx];
void init(){
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(head,-1,sizeof(head));
    top=cnt=k=id=0;
    bridge=inf;
}
void add(ll u,ll v,ll w){
    a[k].next=head[u];
    a[k].v=v;
    a[k].w=w;
    head[u]=k++;
}
void tarjan(ll u,ll pre){
    low[u]=dfn[u]=++id;
    for(int i=head[u];i!=-1;i=a[i].next){
        ll v=a[i].v;
        if(i==(pre^1)) continue;
        if(!dfn[v]){
            tarjan(v,i),low[u]=min(low[u],low[v]);
            if(dfn[u]<low[v]) bridge=min(bridge,a[i].w);
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
int main()
{
    ll n,m,u,v,w;
    while(scanf("%lld%lld",&n,&m),n+m){
        init();
        for(int i=1;i<=m;i++){
            u=read(),v=read(),w=read();
            add(u,v,w),add(v,u,w);
        }
        ll tarjans=0;
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i,-1),tarjans++;
        if(tarjans>1){
            printf("0\n");
            continue;
        }
        if(bridge==inf) bridge=-1;
        else if(bridge==0) bridge=1;
        printf("%lld\n",bridge);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章