HDU 4612 Warm up 连通图缩点

题目大意:给出一个连通图,求再一个边后,剩余的最少桥数。

题目思路:首先进行缩点得到重构后的图,求出重构后树的直径(通过两次BFS求出相距最远的两点间的距离),ans=重构图边数-树的直径

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<vector>
#include<iostream>
#include<queue>
#include<algorithm>
#define MAXSIZE 200005
#define LL long long

using namespace std;

vector<vector<int> >G;
vector<vector<int> >G2;
int vis[MAXSIZE],low[MAXSIZE],dfn[MAXSIZE],pre[MAXSIZE],k,Time,n,m,ans,link;
int dist[MAXSIZE],belong[MAXSIZE],step[MAXSIZE],Stuck[MAXSIZE],block;

void Tarjan(int u,int fa)
{
    low[u]=dfn[u]=++Time;
    pre[u]=fa;
    Stuck[k++]=u;
    int v,len=G[u].size(),op=0;
    for(int i=0;i<len;i++)
    {
        v=G[u][i];
        if(!op && v==fa)//去重边
        {
            op=1;
            continue;
        }
        if(!dfn[v])
        {
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u])
    {
        int temp;
        do{
            temp=Stuck[--k];
            belong[temp]=block;
        }while(temp!=u);
        block++;
    }
}

void Init()
{
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(pre,0,sizeof(pre));
    memset(belong,0,sizeof(belong));
    memset(Stuck,0,sizeof(Stuck));
    ans=0;
    Time=0;
    block=0;
    k=0;
    G.clear();
    G2.clear();
    G.resize(n+2);
    G2.resize(n+2);
}

int BFS(int s,int op)
{
    int now,next;
    queue<int>Q;
    memset(step,-1,sizeof(step));
    step[s]=0;
    Q.push(s);
    while(!Q.empty())
    {
        now=Q.front();
        Q.pop();
        int len=G2[now].size();
        for(int i=0;i<len;i++)
        {
            next=G2[now][i];
            if(step[next]==-1)
            {
                step[next]=step[now]+1;
                Q.push(next);
            }
        }
    }

    if(op==0)
        return now;
    return step[now];
}

int main()
{
    int a,b;
    while(scanf("%d%d",&n,&m),n+m)
    {
        Init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
        }

        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
                Tarjan(i,i);
        }

        for(int i=1;i<=n;i++)
        {
            int fa=pre[i];
            if(belong[i] != belong[fa])
            {
                G2[belong[i]].push_back(belong[fa]);
                G2[belong[fa]].push_back(belong[i]);
            }
        }
        //两边BFS求出树的直径
        int s=BFS(0,0);
        int d=BFS(s,1);
        ans=block-d-1;// 重构后的图的边数等于点数-1,根据贪心策略再减去重构树的直径就是答案
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2017-03-11 16:08  声声醉如兰  阅读(171)  评论(0编辑  收藏  举报