2015 ACM Amman Collegiate Programming Contest--H.Bridges--边双联通分量缩点+直径

n个点m条无向边的一个图,让你加一条边,使得桥数最少,输出最少桥的个数。

先缩点,然后图中所有的点都成了“桥”,然后我们求出缩点的个数sig,此时有sig-1条桥,然后我们连一个边,使其成为最大环,当然就是连接直径的两端点啦!就是sig-1-zhijing。

//DFS版
#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define INF 0x3f3f3f3f
using namespace std;
const int MAXN = 3e5+5;
const int MAXM = 7e5+5;
struct node
{
    int from,to,next;
} e[150050*3];
struct ZhiJing
{
    int head[150050];
    int vis[150050];
    int cont;
    int mx,root;
    void init()
    {
        cont=0;
        memset(head,-1,sizeof(head));
    }
    void add(int from,int to)
    {
        e[cont].to=to;
        e[cont].next=head[from];
        head[from]=cont++;
    }
    void Dfs(int u,int from,int depth)
    {
        vis[u]=1;
        if(depth>mx)
        {
            mx=depth;
            root=u;
        }
        for(int i=head[u]; i!=-1; i=e[i].next)
        {
            int v=e[i].to;
            if(vis[v]==0)
                Dfs(v,u,depth+1);
        }
    }
    void dfs(int u,int from,int depth)
    {
        vis[u]=1;
        mx=max(mx,depth);
        for(int i=head[u]; i!=-1; i=e[i].next)
        {
            int v=e[i].to;
            if(vis[v]==0)
                dfs(v,u,depth+1);
        }
    }
    int solve()
    {
        mx=0;
        root=1;
        memset(vis,0,sizeof(vis));
        Dfs(1,-1,0);
        mx=0;
        memset(vis,0,sizeof(vis));
        dfs(root,-1,0);
        return mx;
    }
 
} zhi;
struct EDGE
{
    int to,next,id;
} edges[MAXM*2];
stack<int> stk;
struct BianSuoDain
{
    int n,m,sig,color[MAXN],heads[MAXN],edge_num,Inx,dfn[MAXN],low[MAXN],used[MAXM];
    void init(int n1,int m1)
    {
        n=n1;
        m=m1;
        sig=0;
        edge_num=0;
        Inx=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(used,0,sizeof(used));
        memset(heads,255,sizeof(heads));
        for(int i=0; i<=n; i++)
            color[i]=0;
        while(stk.size())
            stk.pop();
        //
    }
    void add_edge(int u,int v)
    {
        edges[edge_num].to = v;
        edges[edge_num].next = heads[u];
        heads[u] = edge_num++;
        //printf("---");
    }
    void tarjan(int u,int fa)
    {
        dfn[u] = low[u] = ++Inx;
        stk.push(u);
        for(int i=heads[u]; i!=-1; i=edges[i].next)
        {
            // cout<<i<<endl;
            int v = edges[i].to;
            if(v==fa)
                continue;
 
            if(!dfn[v])
            {
                tarjan(v,u);
                low[u] = min(low[u],low[v]);
            }
            else
                low[u] = min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u])
        {
            //set<int> tmp_ver_set;//记录点的数量
            //set<int> tmp_edge_set;//记录边的数量
            //tmp_ver_set.insert(u);
            int x;
            sig++;
            do
            {
 
                x = stk.top();
                color[x]=sig;
                //printf("%d--ddd-%d\n",x,color[x]);
                stk.pop();
                //tmp_edge_set.insert(edge[x].id);
                //tmp_ver_set.insert(edge[x].to);
                //在这里存储一个点双联通分量里的边、点
            }
            while(x!=u);
            //if(tmp_edge_set.size()==tmp_ver_set.size())
            // for(set<int>::iterator it=tmp_edge_set.begin(); it!=tmp_edge_set.end(); it++)
            //ans.push_back(*it);//把边加进去
        }
        //cout<<"pp"<<endl;
    }
 
    void new_Map()
    {
        //cout<<"asdaq"<<endl;
        zhi.init();
        for(int i=1; i<=n; i++)
        {
            for(int j=heads[i]; j!=-1; j=edges[j].next)
            {
                //cout<<"|||"<<endl;
                int v=edges[j].to;
                if(color[i]!=color[v])
                {
                    //printf("%d--%d\n",i,v);
                    //printf("%d--%d\n",color[i],color[v]);
                    //cout<<"asda"<<endl;
                    zhi.add(color[i],color[v]);
                    zhi.add(color[v],color[i]);
                }
            }
        }
        //cout<<"AsdfsasdSA"<<endl;
        int ans1=sig-1-zhi.solve();
        printf("%d\n",ans1);
    }
    void work()
    {
        for(int i=1; i<=n; i++)
        {
            if(!dfn[i])
            {
                //cout<<"++"<<endl;
                tarjan(i,i);
            }
        }
        //cout<<sig<<endl;
        new_Map();
    }
} bian;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d %d",&n,&m);
        bian.init(n,m);
        for(int i=1; i<=m; i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            bian.add_edge(u,v);
            bian.add_edge(v,u);
        }
        bian.work();
    }
    /*
    3
    3 3
    1 2
    2 3
    3 1
    7 7
    1 2
    2 3
    3 1
    3 4
    4 5
    4 6
    6 7
    */
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值