zoukankan      html  css  js  c++  java
  • poj-3177(并查集+双联通分量+Tarjan算法)

    题目链接:传送门

    思路:

    题目要将使每一对草场之间都有至少两条相互分离的路径,所以转化为(一个有桥的连通图至少加几条边才能变为双联通图?)

    先求出所有的桥的个数,同时将不同区块收缩成一个点(利用并查集),之后一个图变为了一颗树;

    然后在统计树中度数为1的点的个数,记为cnt,则至少添加(cnt+1)/2条边。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int maxn = 10010;
    struct Edge{
        int u,v;
    };
    Edge tmp;
    vector <Edge> ee;
    int num[maxn],vis[maxn],low[maxn],fa[maxn],tog[maxn],m,n,tim;
    vector <int> vc[maxn];
    void Init()
    {
        memset(vis,0,sizeof(vis));
        memset(num,0,sizeof(num));
        memset(low,0,sizeof(low));
        memset(fa,0,sizeof(fa));
        memset(tog,0,sizeof(tog));
        ee.clear();
        for(int i=0;i<maxn;i++) vc[i].clear();
        tim=1;
    }
    int MIN(int x,int y)
    {
        return x<y?x:y;
    }
    int f(int x)
    {
        if(fa[x]==0) return x;
        else return fa[x]=f(fa[x]);
    }
    void Tarjan(int v,int pre)
    {
        int i,w;
        vis[v]=1;
        low[v]=num[v]=tim++;
        for(i=0;i<vc[v].size();i++){
            w=vc[v][i];
            if(!vis[w]){
                Tarjan(w,v);
                low[v]=MIN(low[v],low[w]);
                if(low[w]>num[v]){ //找到桥 
                    tmp.u=v;tmp.v=w;
                    ee.push_back(tmp);
                }
                else{ //不是桥,就缩点 
                    int t1=f(v);
                    int t2=f(w);
                    if(t1!=t2) fa[t2]=t1;
                }
            }
            else if(pre!=w) low[v]=MIN(low[v],num[w]); 
        }
    }
    int main(void)
    {
        int i,j,x,y;
        while(~scanf("%d%d",&n,&m)){
            Init();
            for(i=0;i<m;i++){
                scanf("%d%d",&x,&y);
                vc[x].push_back(y);
                vc[y].push_back(x);
            }
            Tarjan(1,-1);
            for(i=0;i<ee.size();i++){ //统计树中的度数为1的顶点的个数 
                int t1=f(ee[i].u);
                int t2=f(ee[i].v);
                tog[t1]++;tog[t2]++;
            }
            int cnt=0;
            for(i=1;i<=n;i++)
            if(tog[i]==1) cnt++;
            cnt=(cnt+1)/2;
            printf("%d
    ",cnt);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    python微信机器人
    爬取糗事百科,微信自动发送
    验证码破解
    [Python]机器学习【推荐】
    [Python]利用jieba.analyse进行 关键词 提取
    《将博客搬至CSDN》
    [极限测试]第一日进度
    [Python]调用百度API进行自然语言处理 标签、关键字 以及 词法分析
    学习进度报告【第三周】
    [Python]调用百度地图API对地点进行搜索,利用 JSON 返回纬度/行政区域编号
  • 原文地址:https://www.cnblogs.com/2018zxy/p/10357599.html
Copyright © 2011-2022 走看看