首页 > 其他 > 详细

Warm up——缩点、树上直径

时间:2019-10-16 22:13:06      阅读:62      评论:0      收藏:0      [点我收藏+]

题目链接

题意:

给出n个点和m条边的无向图,存在重边,问加一条边以后,剩下的桥的数量最少为多少。

题解:

把这个无向图缩点后会得到一个只由桥来连接的图(可以说这个图中的所有边都是桥,相当于一棵树),

然后我们只需要找出来这棵树的最大直径(即相距最远的两个点)。

因为如果我们把直径所在的两个端点连起来,这样减少的桥最多。

所以 答案就是 桥的数量 - 树的直径上桥的数量

原图求桥的数量,缩点后建立新的图求直径

技术分享图片

 

 

代码:

技术分享图片
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
using namespace std;

const int maxn = 200005;//点数
const int maxm = 2001000;//边数,因为是无向图,所以这个值要*2

struct Edge
{
    int to,next;
    bool cut;//是否是桥标记
} edge[maxm],edge1[maxm];
int head[maxn],tot,head1[maxn],tot1;
int low[maxn],dfn[maxn],Stack[maxn],belong[maxn];//belong数组的值是1~scc
int Index,top;
int scc;//边双连通块数/强连通分量的个数
bool Instack[maxn];
int bridge;//桥的数目
bool cut[maxn];
void addedge(int u,int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    edge[tot].cut=false;
    head[u] = tot++;
}
void add(int u,int v)
{
    edge1[tot1].to = v;
    edge1[tot1].next = head1[u];
    head1[u] = tot1++;
}
void Tarjan(int u,int pre)
{
    int v;
    low[u] = dfn[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    int son=0;
    int flag=0;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(v == pre && !flag)
        {
            flag++;
            continue;
        }
        if( !dfn[v] )
        {
            son++;
            Tarjan(v,u);
            if( low[u] > low[v] )low[u] = low[v];
            if(low[v] > dfn[u])
            {
                bridge++;
                edge[i].cut = true;
                edge[i^1].cut = true;
            }
            if(u == pre && son > 1)cut[u] = true;
            if(u != pre && low[v] >= dfn[u])cut[u] = true;

        }
        else if( Instack[v] && low[u] > dfn[v] )
            low[u] = dfn[v];
    }

    if(low[u] == dfn[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            belong[v] = scc;
        }
        while( v!=u );
    }

}
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}
void init1()
{
    tot1 = 0;
    memset(head1,-1,sizeof(head1));
}
int deep[maxn];

int bfs(int s)
{
    queue<int> Q;
    memset(deep,0,sizeof deep);
    deep[s] = 1;
    Q.push(s);
    int ans = s;
    while(!Q.empty())
    {
        int u = ans = Q.front();
        Q.pop();
        for(int i=head1[u]; ~i; i=edge1[i].next)if(!deep[edge1[i].to])
            {
                int v=edge1[i].to;
                deep[v] = deep[u]+1;
                Q.push(v);
            }
    }
    return ans;

}

void solve(int n)
{
    memset(dfn,0,sizeof(dfn));
    memset(Instack,false,sizeof(Instack));
    memset(cut,0,sizeof cut);
    Index = top = scc = 0;
    bridge = 0;


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

    init1();
    for(int i=1; i<=n; i++)
    {
        for(int j=head[i]; ~j; j=edge[j].next)
        {
            int u=belong[i];
            int v=belong[edge[j].to];
            if(u!=v)
            {
                add(u,v);
                add(v,u);
            }
        }
    }
    int ans=deep[bfs(bfs(1))];

    printf("%d\n",scc-1-(ans-1));
}


int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m) && (n || m))
    {
        init();
        while(m--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        solve(n);
    }
    return 0;
}
/*
4 4
1 2
1 3
1 4
2 3
0 0
*/
View Code

 

Warm up——缩点、树上直径

原文:https://www.cnblogs.com/j666/p/11688483.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!