[ tarjan ] Codeforces700C Break Up

本文介绍了一种通过图算法解决特定网络连通性问题的方法:删除某条边后,寻找使得两个指定节点不连通的最小权值边集。通过深度优先搜索和Tarjan算法确定关键路径和桥边,最终找到最小成本方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先枚举删一条边,然后找出新图中所有的桥,可以发现如果一条边是桥且在 sst 的路径上,将其删去一定会使 sst 不连通。求个最小值就好了。

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
const int M=30010;
int k,n,m,S,T,x,y;
int w[M];
int t[M<<1],nx[M<<1],h[N],num=1;
int Ans=INT_MAX,c1,c2;
int dfn[N],low[N],tc;
bool v[N],b[M];
vector<int>g,G;
inline void Add(int x,int y){
    t[++num]=y;nx[num]=h[x];h[x]=num;
}
bool Dfs(int x,int y,int d){
    v[x]=1;
    if(x==y)return 1;
    for(int i=h[x];i;i=nx[i])
    if((i>>1)!=d&&!v[t[i]]&&Dfs(t[i],y,d)){
        g.push_back(i>>1);
        return 1;
    }
    return 0;
}
bool Dfs1(int x,int y){
    v[x]=1;
    if(x==y)return 1;
    for(int i=h[x];i;i=nx[i])
    if(!v[t[i]]&&Dfs1(t[i],y)){
        G.push_back(i>>1);
        return 1;
    }
    return 0;
}
void Tarjan(int x,int y,int d){
    dfn[x]=low[x]=++tc;
    bool fl=0;
    for(int i=h[x];i;i=nx[i])
    if((i>>1)!=d){
        if(t[i]==y&&!fl){
            fl=1;
            continue;
        }
        if(!dfn[t[i]]){
            Tarjan(t[i],x,d);
            low[x]=min(low[x],low[t[i]]);
            if(low[t[i]]>dfn[x])b[i>>1]=1;
        }else low[x]=min(low[x],dfn[t[i]]);
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&S,&T);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&w[i]),Add(x,y),Add(y,x);
    if(!Dfs1(S,T)){
        printf("0\n0\n");
        return 0;
    }
    for(int i=0;i<G.size();i++){
        x=G[i];
        g.clear();
        memset(v,0,sizeof(v));
        if(!Dfs(S,T,x)){
            if(w[x]<Ans)Ans=w[x],c1=x,c2=0;
        }else{
            memset(b,0,sizeof(b));
            memset(dfn,0,sizeof(dfn));
            tc=0;
            for(int j=1;j<=n;j++)
            if(!dfn[j])Tarjan(j,0,x);
            for(int j=0;j<g.size();j++)
            if(b[g[j]]&&w[x]+w[g[j]]<Ans)Ans=w[x]+w[g[j]],c1=x,c2=g[j];
        }
    }
    if(Ans==INT_MAX)puts("-1");else{
        printf("%d\n",Ans);
        if(!c2)printf("1\n%d\n",c1);else printf("2\n%d %d\n",c1,c2);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值