[kuangbin带你飞]专题九 连通图 题解 慢慢更新

开一个大坑 网络流专题啥的晚点再补把
先把连通图弄懂

Network of Schools POJ - 1236 tarjan缩点模板题

题目思路

题目给了两个问题
给多少个学校就能让其他所有学校都能收到
连接多少个学校能使最后给任意一个学校其他所有学校都能
用tarjan进行缩点 在统计随点后图上每个点的出入度
入度为0的点的数量就是第一个答案
max(入度为0的点的数量,入度为0的点的数量)就是第二个答案
还有就是不要忘记原本就是强连通图的情况

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;

struct node
{
    int to,next;
}e[maxn];
int n,m,len,first[maxn];
int dfn[maxn],low[maxn],belong[maxn],in[maxn],out[maxn];
int ins[maxn],sz[maxn],st[maxn];
int block,id,tp;

void add(int u,int v)
{
    e[len].to=v;
    e[len].next=first[u];
    first[u]=len++;
}

void init()
{
    id=tp=block=0;
    len=0;
    ms(first,-1);
    ms(low,0);
    ms(dfn,0);
    ms(sz,0);
    ms(out,0);
    ms(in,0);
}

void tarjan(int u)
{
    dfn[u]=low[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(ins[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u])
    {
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            sz[block]++;
        }while(u!=v);
    }
}

int main()
{
    int n;

    while(~scanf("%d",&n))
    {
        ms(first,-1);init();
        for(int i=1;i<=n;i++)
        {
            int x;
            while(scanf("%d",&x))
            {
                if(x!=0)
                    add(i,x);
                else
                    break;
            }
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        for(int i=1;i<=n;i++)
        {
            for(int j=first[i];j!=-1;j=e[j].next)
            {
                int u=i,v=e[j].to;
                if(belong[u]!=belong[v])
                {
                    in[belong[v]]++;
                    out[belong[u]]++;
                }
            }
        }
        int ii=0,oo=0;
        if(block==1)
        {
            printf("1\n0\n");
        }else
        {
            for(int i=1;i<=block;i++)
            {
                if(in[i]==0)
                    ii++;
                if(out[i]==0)
                    oo++;

            }
            printf("%d\n%d\n",ii,max(oo,ii));
        }
    }

}

Network UVA - 315 求割点模板题

题目思路

题目要求的是图的割点
套tarjan求割点的板子就好了
读入有点毒瘤 但慢慢写也还好

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;

struct node
{
    int to,next;
}e[maxn];
int n,len,first[maxn],dfn[maxn],low[maxn],st[maxn],indexx,ins[maxn];
int cot,vis[maxn];
void add(int u,int v)
{
    e[len].to=v;
    e[len].next=first[u];
    first[u]=len++;
}

void init()
{
    len=indexx=0;
    cot=0;
    ms(first,-1);
    ms(dfn,0);
    ms(low,0);
    ms(ins,0);
    ms(vis,0);
}

void tarjan(int u,int fa)
{
    int ch=0;
    low[u]=dfn[u]=++indexx;
    ins[u]=1;
    for(int i=first[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)continue;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]&&u!=fa)vis[u]=1;//这里似乎不能直接统计 可能会有重复
            if(u==fa)ch++;
        }else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(ch>=2&&u==fa)vis[u]=1;
}

int main()
{

    while(~scanf("%d",&n)&&n)
    {
        init();
        int x;
        while(~scanf("%d",&x)&&x)
        {
            int u;
            char tem;
            while(~scanf("%d%c",&u,&tem))
            {
                add(x,u),add(u,x);
                if(tem=='\n')break;
            }

        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i,i);
        for(int i=1;i<=n;i++)
            if(vis[i]==1)
                cot++;
        printf("%d\n",cot);
    }

}

Critical Links UVA - 796 求桥模板题

题目思路

这题就是要找桥 套个板子就好
有几个需要注意的地方
1 输入的时候可能会有重边
一开始准备每次建边只见一个方向这样就不会有重边了
但是这样不好输出
所以就改成了 只让起点小的建边
2 输出的时候还要单独换下行 不然会报pe 就挺恶心人的
uva的题目每次交都要等好久甚至还submit failed
头疼得很

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;

struct node
{
    int to,next,from;
}e[maxn];

struct point
{
    int a,b;
}ans[maxn];

int n,len,first[maxn],dfn[maxn],low[maxn],st[maxn],indexx,ins[maxn];
int cot,vis[maxn],bridge[maxn];
void add(int u,int v)
{
    e[len].to=v;
    e[len].from=u;
    e[len].next=first[u];
    first[u]=len++;
}

void init()
{
    len=indexx=0;
    cot=0;
    ms(first,-1);
    ms(dfn,0);
    ms(low,0);
    ms(ins,0);
    ms(vis,0);
    ms(bridge,0);
}

void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++indexx;
    for(int i=first[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u])
            {
                //cot++;
                bridge[i]=bridge[i^1]=1;
            }
        }else if(v!=fa)
            low[u]=min(low[u],dfn[v]);
    }
}
int main()
{

    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n;i++)
        {
            int x,m;
            scanf("%d (%d)",&x,&m);
            for(int j=1;j<=m;j++)
            {
                int v;
                scanf("%d",&v);
                if(x>v)continue;
                add(x,v),add(v,x);
            }
        }
        for(int i=0;i<n;i++)
            if(!dfn[i])
                tarjan(i,-1);
        for(int i=0;i<len;i+=2)
        {
            if(bridge[i])
            {
                ans[++cot].a=e[i].from;
                ans[cot].b=e[i].to;
            }
        }
        printf("%d critical links\n",cot);
        for(int i=1;i<=cot;i++)
            printf("%d - %d\n",ans[i].a,ans[i].b);
        printf("\n");
    }
}

Caocao’s Bridges HDU - 4738 找桥的最小权值

题目思路

这题也是拿tarjan找桥 但是坑点挺多的 看了下面的提示才知道
这题首先要找桥的最小权值
然后如果本身就不是连通图 那么直接输出0
如果桥最小权值是0 也需要带一个人 所以直接输出1
如果没桥输出-1
剩下的情况直接输出
说实话如果没提示的话得wa到明天去

ac代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <utility>
#define pi 3.1415926535898
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
#define eps 1e-6
#define ms(a,b) memset(a,b,sizeof(a))
#define legal(a,b) a&b
#define print1 printf("111\n")
using namespace std;
const int maxn = 1e6+10;
const int inf = 0x3f3f3f3f;
const ll llinf =0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;

struct node
{
    int to,next,v;
}e[maxn];

int n,m,ans,len,first[maxn],dfn[maxn],low[maxn],st[maxn],indexx,ins[maxn];
int cot,vis[maxn],bridge[maxn];
void add(int u,int v,int w)
{
    e[len].to=v;
    //e[len].from=u;
    e[len].v=w;
    e[len].next=first[u];
    first[u]=len++;
}

void init()
{
    len=indexx=0;
    cot=0;
    ans=inf;
    ms(first,-1);
    ms(dfn,0);
    ms(low,0);
    ms(ins,0);
    ms(vis,0);
    ms(bridge,0);
}

void tarjan(int u,int edge)
{
    dfn[u]=low[u]=++indexx;
    for(int i=first[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v,i);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u])
            {
                //cot++;
                ans=min(ans,e[i].v);
            }
        }else if((i^1)!=edge)
            low[u]=min(low[u],dfn[v]);
    }
}
int main()
{

    while(~scanf("%d%d",&n,&m)&&n+m)
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        int tim=0;
        for(int i=1;i<=n;i++)
            if(!dfn[i])
            {
                tarjan(i,-1);
                tim++;
            }
        if(tim>1)
            printf("0\n");
        else if(ans==inf)
            printf("-1\n");
        else if(ans==0)
            printf("1\n");
        else
            printf("%d\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
并查集是一种常用的数据结构,用于管理一个不相交集合的数据。在并查集中,每个元素都有一个父节点指向它所属的集合的代表元素。通过查找和合并操作,可以判断两个元素是否属于同一个集合,并将它们合并到同一个集合中。 在解决某些问题时,可以使用并查集进行优化。例如,在区间查询中,可以通过优化并查集的查询过程,快速找到第一个符合条件的点。 对于拆边(destroy)操作,一般的并查集无法直接实现这个功能。但是可以通过一个巧妙的方法来解决。首先,记录下所有不会被拆除的边,然后按照逆序处理这些指令。遇到拆边操作时,将该边重新加入并查集中即可。 在实现并查集时,虽然它是一种树形结构,但只需要使用数组就可以实现。可以通过将每个元素的父节点记录在数组中,来表示元素之间的关系。通过路径压缩和按秩合并等优化策略,可以提高并查集的效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [「kuangbin专题五并查集专题题解](https://blog.csdn.net/weixin_51216553/article/details/121643742)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [并查集(详细解释+完整C语言代码)](https://blog.csdn.net/weixin_54186646/article/details/124477838)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值