gym Bridges

题目大意:给你一个无向图,问我们最多加一条边使得图的桥的数量最小,输出最小数量

解题思路:先将图缩点,我们就得到一个无环图,然后我们只需找到最长链,将其首尾相连即可减少对多的桥,减少的数量为链的长度,即树的直径。(ps:注释部分为并查集缩点)

代码:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<set>
#include<stack>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
#define inf 0x3fffffff
//const double pi=acos(-1);
typedef long long LL;
#define N 100005

int low[N],pre[N],scc[N],dfs_clock,scc_cnt;
int fa[N];
int cnt;
int ans;
int root;
struct node
{
    int st,en,next;
    //bool fg;
} e[2*N],e1[2*N];
int p[N],num;
void init()
{
    memset(p,-1,sizeof(p));
    num=0;
}
void add(int st,int en)
{
    e[num].st=st;
    e[num].en=en;
    //e[num].fg=false;
    e[num].next=p[st];
    p[st]=num++;
}
int p1[N],num1;
void init1()
{
    memset(p1,-1,sizeof(p1));
    num1=0;
}
void add1(int st,int en)
{
    e1[num1].st=st;
    e1[num1].en=en;
    e1[num1].next=p1[st];
    p1[st]=num1++;
}
//int Find(int x)
//{
//    if(fa[x]!=x)
//        fa[x]=Find(fa[x]);
//    return fa[x];
//}
//void Union(int u,int v)
//{
//    int x=Find(u);
//    int y=Find(v);
//    if(x!=y)
//    {
//        fa[y]=x;
//    }
//}
stack<int>s;
int dfs(int u,int fa)
{
    pre[u]=low[u]=++dfs_clock;
    s.push(u);
    for(int i=p[u]; i+1; i=e[i].next)
    {
        int v=e[i].en;
        if(!pre[v])
        {
            low[v]=dfs(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>pre[u])
            {
//                e[i].fg=1;
//                e[i^1].fg=1;
                cnt++;
            }
//            else
//            {
//                Union(u,v);
//            }
        }
        else if(pre[v]<pre[u]&&v!=fa)
        {
            low[u]=min(low[u],pre[v]);
        }
    }
    if(low[u]==pre[u])
    {
       scc_cnt++;
        while(1)
        {
           int x=s.top();
            s.pop();
            scc[x]=scc_cnt;
            if(u==x)
                break;
       }
    }
    return low[u];
}
void find_scc(int n)
{
    dfs_clock=cnt=scc_cnt=0;
    memset(pre,0,sizeof(pre));
    for(int i=0;i<=n;i++)
        fa[i]=i;
    dfs(1,-1);
}
int dfs1(int st,int fa,int tem)
{
    if(ans<tem)
    {
        ans=tem;
        root=st;
    }
    for(int i=p1[st]; i+1; i=e1[i].next)
    {
        int en=e1[i].en;
        if(en==fa)continue;
        dfs1(en,st,tem+1);
    }
    return root;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        init();
        init1();
        scanf("%d%d",&n,&m);
        for(int i=1; i<=m; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
        find_scc(n);
        if(cnt==0)
        {
            printf("0\n");
            continue;
        }
        //int tot=num;
        int xx;
//        for(int i=0;i<tot;i++)
//        {
//            if(e[i].fg)
//            {
//                int u=Find(e[i].st);
//                int v=Find(e[i].en);
//                add1(u,v);
//                xx=u;
//            }
//        }
       for(int i=1; i<=n; i++)
        {
           for(int j=p[i]; j+1; j=e[j].next)
           {
               int en=e[j].en;
               if(scc[i]!=scc[en])
               {
                   add1(scc[i],scc[en]);
                   //add1(scc[en],scc[i]);
               }
            }
        }
        ans=0;
        int x=dfs1(1,-1,0);
        ans=0;
        dfs1(x,-1,0);
        printf("%d\n",cnt-ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值