hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就能够构成了边双连通)。

先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少。这里学习了树的直径求法:第一次选随意起点U,进行bfs,到达最远的一个点v(level最深)该点必定是树的直径的一个端点,,再从该点出发,bfs,到最深的一点。该点深度就是直径。

(证明:先如果u。是直径上一点,S,T是直径的端点。设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v;若u不是直径上一点。设u到直径上的一点为x。同理易证。

最后 缩点后树的边-直径就可以。

再说说这次,哎。先是爆栈,没有在C++申请空间。。。 无向图的tarjian太不熟练了。非常久没敲了。

。。。

注意点:无向图求边双连通,缩点,能够这样:

法1:必需用前向星来保存边,然后标记訪问边(同一时候标记反向边)的方法来处理。这样,重边的话。就在字自然在一个边通分量中了。(要求边数能够用数组存下),这样不用。=-father来推断。

法2,重边视为单边(仅仅有俩个点不连通),不标记边,多一个參数father。在返祖边更新我的时候,加推断!=father。

#pragma comment(linker, "/STACK:10240000000000,10240000000000")        //申请空间
#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<stack>
using namespace std;
const int maxv=300010;
int dfn[maxv];int low[maxv];int visited[maxv];
int ins[maxv];stack<int>sta;int scc[maxv];
int times=0;int block=0;
int n,m;
int minn(int a,int b)
{
    if(a<=b)return a;
    return b;
}
int nume=0;int e[2000500][2];int head[maxv];
void inline adde(int i,int j)                 //原图
{
    e[nume][0]=j;e[nume][1]=head[i];head[i]=nume++;
    e[nume][0]=i;e[nume][1]=head[j];head[j]=nume++;
}
int nume2=0;int newg[2000500][2];int head2[maxv];
void inline adde2(int i,int j)                //新图
{
    newg[nume2][0]=j;newg[nume2][1]=head2[i];head2[i]=nume2++;
    newg[nume2][0]=i;newg[nume2][1]=head2[j];head2[j]=nume2++;
}
bool marke[2001000];          //标记边的訪问
void tarjan(int u)
{
    dfn[u]=low[u]=++times;
    ins[u]=1;
    sta.push(u);
    for(int i=head[u];i!=-1;i=e[i][1])
    {
        int child=e[i][0];
         if(marke[i])continue;            //注意放在这里,否则以下的会更新。起不了作用
        if(visited[child]==0)
        {
            visited[child]=1;
            marke[i]=marke[i^1]=1;       //标记双向
            tarjan(child);
            low[u]=minn(low[u],low[child]);
        }
        else if(ins[child])
        {
            low[u]=minn(dfn[child],low[u]);
        }
   }
    if(low[u]==dfn[u])          //同一个边双连通
   {
       block++;
       int cur;
       do
       {
           cur=sta.top();
           ins[cur]=0;
           sta.pop();
           scc[cur]=block;
       }while(cur!=u);
   }
}
void rebuild()
{
    for(int i=1;i<=n;i++)             //遍历全部边。来又一次建图,若在同一个边双连通中,则有边。
    {
        for(int j=head[i];j!=-1;j=e[j][1])
        {
             int ch=e[j][0];
            if(scc[i]!=scc[ch])
                 adde2(scc[i],scc[ch]);
        }
    }
}
int lev[maxv];
void bfsgetlev(int ss)               //BFS分层
{
    memset(lev,0,sizeof(lev));
    memset(visited,0,sizeof(visited));
    queue<int>q;
    q.push(ss);
    visited[ss]=1;
    while(!q.empty())
    {
        int cur=q.front();
        q.pop();
        for(int i=head2[cur];i!=-1;i=newg[i][1])
        {
            int vv=newg[i][0];
             if(!visited[vv])
             {
                 lev[vv]=lev[cur]+1;
                 q.push(vv);
                 visited[vv]=1;
             }
        }
    }
    return ;
}
void init()
{

          block=times=0;nume=0;nume2=0;
          memset(marke,0,sizeof(marke));
          memset(dfn,0,sizeof(dfn));
          memset(low,0,sizeof(low));
          memset(visited,0,sizeof(visited));
          memset(head,-1,sizeof(head));
          memset(head2,-1,sizeof(head2));

}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
     {
         init();
        int a,b;
        for(int i=0;i<m;i++)
        {
           scanf("%d%d",&a,&b);
             adde(a,b);
        }
        visited[1]=1;
        tarjan(1);
        rebuild();
          int ans=0;
             bfsgetlev(1);
            int froms=0;
           int maxx=-1;
            for(int i=1;i<=block;i++)
            {
                if(lev[i]>maxx)
                {
                    maxx=lev[i];
                    froms=i;
                }
            }
             bfsgetlev(froms);                   //最远点(直直径的一个端点)
            for(int i=1;i<=block;i++)
            {
                if(lev[i]>maxx)
                {
                    maxx=lev[i];
                }
            }
              ans=block-1-maxx;
            printf("%d\n",ans);

      }
       return 0;
}
时间: 2024-10-09 10:41:27

hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径的相关文章

hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v(level最深)该点必然是树的直径的一个端点,,再从该点出发,bfs,到最深的一点,该点深度就是直径.(证明:先假设u,是直径上一点,S,T是直径的端点,设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v:若u不是直径上一点,设u到直径上的一点为x,同理易证. 最后 缩

hdu4612 连通性,求树的直径,加一边求最少桥

http://acm.hdu.edu.cn/showproblem.php?pid=4612 Problem Description N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels. If we can isolate

ural 1145 Rope in the Labyrinth 图中 bfs求树的直径

1145. Rope in the Labyrinth Time limit: 0.5 second Memory limit: 64 MB A labyrinth with rectangular form and size m × n is divided into square cells with sides' length 1 by lines that are parallel with the labyrinth's sides. Each cell of the grid is

HDU 4612--Warm up 【无向图边双连通求桥数 &amp;&amp; 缩点后重建图求树的直径】

Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 4830    Accepted Submission(s): 1086 Problem Description N planets are connected by M bidirectional channels that allow instant transpor

并查集的应用之求解无向图中的连接分量个数

一,介绍 本文使用数据结构:并查集 来实现 求解无向图的连通分量个数. 无向图的连通分量就是:无向图的一个极大连通子图,在极大连通子图中任意两个顶点之间一定存在一条路径.对于连通的无向图而言,只有一个连通分量. 二,构造一个简单的无向图 这里仅演示求解无向图的连通分量,因此需要先构造一个无向图.图由顶点和边组成,并采用图的邻接表形式存储.顶点类和边类的定义如下: 1 private class Vertex{ 2 private Integer vertexLabel; 3 private Li

有向/无向图中搜环

经常遇到一类问题,提供一个图,判断其中是否含环.所谓的环是一条起点与终点相同的路径(至少含有一条边,两个结点).由于不带环的连通图和带环的连通图有着本质的区别,不带环的连通图是树,而树相较于一般的图可以支持更多更高效的算法,比如log2(n)时间复杂度内找任意两点的路径信息,在树上进行树形DP等等. 图按照边是否有向可以分为有向图和无向图.在两类图中找环的时间复杂度均为O(n),而判断是否含环的时间复杂度也是O(n),因此只陈述找环的方法. 无向图找环 无向图找环,因为无向图中没有明确的根,我们

逻辑推理:在一个100条语句的列表中,第n条语句是“在这个列表中,恰有n条语句为假”,可以得出什么结论?

<离散数学及其应用>第六版1.1练习题第43题的个人分析 题目:在一个100条语句的列表中,第n条语句是"在这个列表中,恰有n条语句为假"..........     a)从这些语句中得出什么结论     b) 若第n条语句是"至少有n条语句为家",结论是什么     c)假设包含99条语句,回答b 答案网上都有,我是给出自己的分析过程:(思路大概是:如果这句话话为真,推出这句话的内容为真,由这句话的内容又能推出其余话的是不是为真,再根据其余话的内容来判

三大数据库如何获取表中的第m条到第n条记录(n大于m)

数据库获取表中的第m条到第n条记录(n>m) 1.oracle数据库:(注:tableName.id指的是tableName的主键) select * from (select tableName.*,rownum as con from tableName where rownum <= m order by tableName.id desc) where con >= n; 2.SQLServer数据库:(注:tableName.id指的是tableName的主键) 实现原理解释:

sql数据库中查询第几条到第几条的数据

通用方法: select top 500 * from (select top 1000 * from UserSearchDatas order by ID) a order by ID desc sql数据库中查询第几条到第几条的数据,布布扣,bubuko.com