• POJ3177tarjan缩点_构建双连通图


    POJ3177tarjan缩点_构建双连通图

    根据题意利用tarjan算法进行缩点处理后变成连通无环图,也可以说是一颗树,而且边是双向的所以,如果把这个图变成双连通,那就要对所有度为1的点进行加边处理

    所以步骤如下

    1·tarjan缩点处理

    void tarjan(int u,int pre)
    {
        low[u] = dfn[u] = ++idx;
        for(int v = 1;v <= n;v++)
        {
            if(mp[u][v])
            {
                if(!dfn[v])
                {
                    tarjan(v,u);
                    low[u] = min(low[u],low[v]);
                }
                if(dfn[v] && v != pre)
                {
                    low[u] = min(low[u],dfn[v]);
                }
            }
        }
    }
    

    2· 计算点的度

    for(int i = 1;i <= n;i++)
            {
                for(int j = 1;j <= n;j++)//计算每个点的度
                {
                    if(mp[i][j])
                    {
                        if(low[i] != low[j])//判断不属于一个缩点集合
                        {
                            cnt[low[j]]++;
                        }
                    }
                }
            }
    

     3·计算加的边数

    int ans=0;				//计算度为1的点的个数
    		for(int i = 1;i <= n;i++)
                  {
    			if(cnt[i] == 1) ans++;
    		}
    		printf("%d
    ",(ans + 1) / 2);
    

     嗯嗯tarjan算法差不多啦

    这个题目还出了一个小插曲,就是定义mp时候用的int类型,给爆了,改成bool就好了,其实就该用bool,因为只是一个01存储,但是一想bool和int差的可不是1倍两倍,而是32倍呢(还得看编译器),吓人略略略

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    using namespace std;
    const int maxn = 5010;
    int n,m;
    bool mp[maxn][maxn];
    int low[maxn],dfn[maxn];
    int idx;
    int cnt[maxn];
    /*
    bool 类型的数据 在内存中只有一位 或0 或1
    int 类型的数据 在内存中有16位或32位
    */
    void init()
    {
        memset(low,0,sizeof(low));
        memset(mp,0,sizeof(mp));
        memset(dfn,0,sizeof(dfn));
        memset(cnt,0,sizeof(cnt));
        idx = 0;
    }
    
    void tarjan(int u,int pre)
    {
        low[u] = dfn[u] = ++idx;
        for(int v = 1;v <= n;v++)
        {
            if(mp[u][v])
            {
                if(!dfn[v])
                {
                    tarjan(v,u);
                    low[u] = min(low[u],low[v]);
                }
                if(dfn[v] && v != pre)
                {
                    low[u] = min(low[u],dfn[v]);
                }
            }
        }
    }
    int main()
    {
        int u,v;
        while(~scanf("%d%d",&n,&m))
        {
            init();
            for(int i = 1;i <= m;i++)
            {
                scanf("%d%d",&u,&v);
                mp[u][v] = mp[v][u] = 1;
    
            }
            tarjan(1,1);
            for(int i = 1;i <= n;i++)
            {
                for(int j = 1;j <= n;j++)//计算每个点的度
                {
                    if(mp[i][j])
                    {
                        if(low[i] != low[j])
                        {
                            cnt[low[j]]++;
                        }
                    }
                }
            }
            int ans=0;				//计算度为1的点的个数
    		for(int i = 1;i <= n;i++)
            {
    			if(cnt[i] == 1) ans++;
    		}
    		printf("%d
    ",(ans + 1) / 2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    java图片加文字
    [转]NetBeans优化技巧 提升启动速度
    重建win7桌面图标缓存
    负载测试(Load Test)
    乐观锁与悲观琐的区别
    事物锁表问题
    建立silverlight安装环境
    持续集成ccnet
    C# AppDomain
    Windows Services
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9407010.html
Copyright © 2020-2023  润新知