HDU 4612 双联通分量+树的直径

点击打开链接

题意:给一个无向联通图,里面可能有重边,问添加一条边后,使得图中的桥最小,将桥的数量输出

思路:刚刚读完题,就有了思路去写,无非就是将联通图双联通分量后缩点,然后求一条最长的路,首尾相连,肯定将更多的桥包含使得这些桥不再是桥,很好想的题,但是错了20+什么鬼,md重边这么难处理,醉了~~~,之前的做法是将重边全部找出来,希望数据弱点水过去算了,TLE好样的,那么我们在处理桥的时候,也就是找桥的时候,如果是桥,我们将这条边标记一下,然后找所有边时加上就行了,在一个就是找树的直径,两次bfs就可以,很简单看看代码把

#include <queue>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=200010;
struct edge{
    int to,num;
    edge(int a,int b){to=a;num=b;}
};
vector<edge>G[maxn];
vector<int>GG[maxn];
int L[maxn],E[maxn],vis[maxn],stack1[maxn];
int n,m,k,kk,cnt;
void dfs(int x,int fa){
    vis[x]=1;L[x]=k;E[x]=k++;stack1[kk++]=x;
    int flag=0;
    for(unsigned int i=0;i<G[x].size();i++){
        edge e=G[x][i];
        if(e.to!=fa){
            if(!vis[e.to]){
                dfs(e.to,x);
                L[x]=min(L[x],L[e.to]);
                if(L[e.to]>E[x]){
                    G[x][i].num=1;
                }
            }else L[x]=min(L[x],E[e.to]);
        }else{
            if(flag) L[x]=min(L[x],E[e.to]);
            flag++;
        }
    }
    if(L[x]==E[x]){
        while(stack1[kk]!=x&&kk>0){
            L[stack1[kk-1]]=L[x];
            kk--;
            vis[stack1[kk]]=0;
        }
    }
}
void tarjan(){
    kk=0;k=1;dfs(1,1);
    for(int i=1;i<=n;i++){
        for(unsigned int j=0;j<G[i].size();j++){
            edge e=G[i][j];
            if(L[i]!=L[e.to]&&e.num==1){
                cnt++;
                GG[L[i]].push_back(L[e.to]);
                GG[L[e.to]].push_back(L[i]);
            }
        }
    }
}
int dis[maxn],v[maxn];
void bfs(int s){
    memset(dis,0,sizeof(dis));
    memset(v,0,sizeof(v));
    v[s]=1;dis[s]=0;
    queue<int>que;
    que.push(s);
    while(!que.empty()){
        int u=que.front();que.pop();
        for(unsigned int i=0;i<GG[u].size();i++){
            int t=GG[u][i];
            if(v[t]==0){
                v[t]=1;
                dis[t]=dis[u]+1;
                que.push(t);
            }
        }
    }
}
int slove(int s){
    int max1=0,pos=s;
    bfs(s);
    for(int i=1;i<=n;i++){
        if(dis[i]>max1){
            pos=i;max1=dis[i];
        }
    }
    bfs(pos);
    int ans=0;
    for(int i=1;i<=n;i++){
        if(dis[i]>ans) ans=dis[i];
    }
    return ans;
}
int main(){
    int flag,a,b;
    while(scanf("%d%d",&n,&m)!=-1){
        if(n==0&&m==0) break;
        for(int i=0;i<maxn;i++){
            G[i].clear();GG[i].clear();vis[i]=0;
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a,&b);
            if(a==b) continue;
            G[a].push_back(edge(b,0));
            G[b].push_back(edge(a,0));
        }
        cnt=0;tarjan();
        int ans1=slove(1);
        printf("%d\n",cnt-ans1);
    }
    return 0;
}
时间: 2024-08-01 04:30:18

HDU 4612 双联通分量+树的直径的相关文章

HDU 4612 Warm up(边双联通求树的直径)

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 some planets from others by breaking only one

hdu 4612 缩点 桥 树的直径

// http://acm.hdu.edu.cn/showproblem.php?pid=4612 // 大致题意: 给n个点和m条边,组成一个无向连通图,问  给我加一条边的权力(可连接任意两点)->让图的桥数量最小,输出此时桥的数量.(2<=N<=200000, 1<=M<=1000000) // 无向环里面的边没有桥,缩点,因为是连通图,所以缩完点后构成了一棵树,每条树边都是一个桥.要加一条边使得加完后图的桥数最小,结合上述,所以选择连接树直径的两端点.ans = 原先

F - Warm up - hdu 4612(缩点+求树的直径)

题意:有一个无向连通图,现在问添加一条边后最少还有几个桥 分析:先把图缩点,然后重构图为一棵树,求出来树的直径即可,不过注意会有重边,构树的时候注意一下 *********************************************************************** #pragma comment(linker, "/STACK:102400000,102400000")#include<stdio.h>#include<string.h

HDU 4738 双联通分量

点击打开链接 题意:给出一个无向图和每条边的权值,现在破坏一条路使得图不再联通,只能破坏一条路,问最少需要的花费,花费为边上的权值,注意的是,图刚开始可能不连通,输出1:花费最小的边为0输出1,其他没什么了 思路:求桥的模版题,在找到一个桥时更新费用最小,对了还有一个可能有重边,简单~~~ #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include

HDU 4738 Caocao&#39;s Bridges(双联通分量+并查集)

大意:有n座岛和m条桥,每条桥上有w个兵守着,现在要派不少于守桥的士兵数的人去炸桥,只能炸一条桥,使得这n座岛不连通,求最少要派多少人去. 思路:我们就是要缩点后直接求桥上人的最少数量.(PS:1.注意图如果不联通直接输出0.2.如果图中的桥上人为0,个那么要让一个人去.3.重边的问题.这里可以忽略) #include<map> #include<queue> #include<cmath> #include<cstdio> #include<stac

hihocoder #1190 : 连通性&#183;四 点双联通分量

http://hihocoder.com/problemset/problem/1190?sid=1051696 先抄袭一下 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho从约翰家回到学校时,网络所的老师又找到了小Hi和小Ho. 老师告诉小Hi和小Ho:之前的分组出了点问题,当服务器(上次是连接)发生宕机的时候,在同一组的服务器有可能连接不上,所以他们希望重新进行一次分组.这一次老师希望对连接进行分组,并把一个组内的所有连接关联的服务器也视为这个组内

[HDOJ4738]Caocao&#39;s Bridges(双联通分量,割边,tarjan)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4738 给一张无向图,每一条边都有权值.找一条割边,使得删掉这条边双连通分量数量增加,求权值最小那条. 注意有重边,ACEveryDay里群巨给的意见是tarjan的时候记录当前点是从哪条边来的. 注意假如桥的权值是0的时候也得有一个人去炸…… 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7

HDU5409---CRB and Graph 2015多校 双联通分量缩点

题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分量则该边一定是桥, 那么我们可以先处理出所有的桥,然后把所有双联通分量缩点,缩点之后就变成了一棵树. 而树上的每一条边都是一个桥, 考虑每条边的输出,删除某一边后肯定会出现两个联通分量, 需要记录两个联通分量中最大的点max1 max2, 如果max1!=n 则答案就是max1 max1+1否则ma

poj3694 network(边双联通分量+lca+并查集)

题    目    传    送    们    在    这 题目大意 有一个由n个点和m条边组成的无向联通图. 现在有Q个操作,每次操作可以在点x,y之间连一条边. 问你每次操作后有多少个多少个桥(即删掉后就会使图不联通的边). 解题思路 根据边双联通的定义,我们知道将边双联通分量缩点后的图,其中的边即为桥. 我们将这个图缩点,就变成了一棵树. 而每次在两个不同的边双联通分量x,y之间加边后,就出现了一个包含x,y的环,其中原先这颗树上x,y的树上最短路径就不在是边. 所以对于每个x,y,我