zoukankan      html  css  js  c++  java
  • Tarjan 做题总结

    这两天Tarjan复习完后把题做了做。洛谷题单《图的连通性》已经做得差不多了。大部分是Tarjan的题,所以写一篇小总结。

    T1 【模板】 缩点

    不多bb。我已经写过关于Tarjan模板的随笔了。传送门

    T2 【模板】割点

    不多bb。传送门

    T3 [USACO03FALL][HAOI2006]受欢迎的牛 G

    题意简述:找到出度为0的点/强连通分量,并输出大小。

    -----------------------------------------------------------------------------------

    先缩点。值得注意的是图中只能有一个出度为0的点。如果有更多的出度为0的点那这些出度为0的点无法互相到达,那么数量就会为0。

    数量在弹栈的时候记录就好。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int head[250005],shabi;
    int st[250005],top;
    int vis[250005],dfn[250005],low[250005],all[250005],color[250005],du[250005];
    int n,m,cnt,tot,x,y,k;
    struct node
    {
        int next,to;
    }edge[550005];
    void add(int from,int to)
    {
        edge[++shabi].next=head[from];
        edge[shabi].to=to;
        head[from]=shabi;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if (ch=='-') f=-1;
            ch=getchar(); 
        }while('0'<=ch&&ch<='9'){
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    void tarjan(int now)
    {
        low[now]=dfn[now]=++cnt;
        vis[now]=1;
        st[++top]=now;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
            else if (vis[to]) low[now]=min(low[now],dfn[to]);
        }
        if (dfn[now]==low[now]){
            tot++;
            do{
                 k=st[top];top--;
                color[k]=tot;
                vis[k]=0;
                all[tot]++;
            }while(k!=now);
        }
    }
    int main()
    {
        n=read(),m=read();
        for (int i=1;i<=m;i++)
        {
            x=read(),y=read();
            add(x,y);
        }
        for (int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
        for (int w=1;w<=n;w++)
            for (int i=head[w];i;i=edge[i].next)
            {
                int to=edge[i].to;
                if (color[w]!=color[to]) du[color[w]]++;
            }
        int flag=0;
        for (int i=1;i<=tot;i++)
        {
            if (!du[i]){
                if (flag){
                    cout<<0;
                    return 0;
                }
                flag=i;
            }
        }
        cout<<all[flag];
        return 0;
    }

    T4 [USACO06JAN]The Cow Prom S

    Tarjan裸题。只要把强连通分量的大小记录下来,如果$num[i]geq 2$那么$ans++$。输出$ans$即可。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=10005;
    const int maxm=50005;
    int dfn[maxn],low[maxn],vis[maxn],num[maxn],pos[maxn],cnt,tot;
    int st[maxn],top;
    int head[maxm],jishu;
    int n,m,ans;
    struct node
    {
        int next,to;
    }edge[maxm];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add(int from,int to)
    {
        edge[++jishu].next=head[from];
        edge[jishu].to=to;
        head[from]=jishu;
    }
    void tarjan(int now)
    {
        vis[now]=1;
        st[++top]=now;
        dfn[now]=low[now]=++cnt;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
            else if (vis[to]) low[now]=min(low[now],dfn[to]);
        }
        if (dfn[now]==low[now])
        {
            tot++;
            while(st[top+1]!=now)
            {
                pos[st[top]]=tot;
                num[tot]++;
                vis[st[top--]]=0;
            }
        }
    }
    int main()
    {
        n=read(),m=read();
        for (int i=1;i<=m;i++)
        {
            int u=read(),v=read();
            add(u,v);
        }
        for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
        for (int i=1;i<=tot;i++) if (num[i]>1) ans++;
        printf("%d",ans);
        return 0;
    }

    T5 [USACO5.3]校园网Network of Schools

    子问题1就是求缩点后入度为零的点的数量。子问题2就是求$max(ans1,ans2)$。

    仔细读读题还是能明白要干什么的。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=10005;
    const int maxm=50005;
    int dfn[maxn],low[maxn],vis[maxn],pos[maxn],cnt,tot;
    int st[maxn],top;
    int head[maxm],jishu;
    int n,fat[maxn][2],k,in[maxn],out[maxn];
    struct node
    {
        int next,to;
    }edge[maxm];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add(int from,int to)
    {
        edge[++jishu].next=head[from];
        edge[jishu].to=to;
        head[from]=jishu;
    }
    void tarjan(int now)
    {
        vis[now]=1;st[++top]=now;
        dfn[now]=low[now]=++cnt;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
            else if (vis[to]) low[now]=min(low[now],dfn[to]);
        }
        if (dfn[now]==low[now])
        {
            tot++;
            while(st[top+1]!=now)
            {
                pos[st[top]]=tot;
                vis[st[top--]]=0;
            }
        }
    }
    int main()
    {
        n=read();
        for (int i=1;i<=n;i++)
        {
            int x=read();
            while(x!=0)
            {
                add(i,x);
                fat[++k][0]=i;
                fat[k][1]=x;
                x=read();
            }
        }
        for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
        for (int i=1;i<=k;i++)
            if (pos[fat[i][0]]!=pos[fat[i][1]]) in[pos[fat[i][1]]]++,out[pos[fat[i][0]]]++;
        int ans1=0,ans2=0;
        for (int i=1;i<=tot;i++)
        {
            if (in[i]==0) ans1++;
            if (out[i]==0) ans2++;
        }
        if (tot==1) cout<<1<<endl<<0;
        else cout<<ans1<<endl<<max(ans1,ans2);
        return 0;
    }

    T6 上白泽慧音

    在弹栈的时候记录强连通分量的大小和字典序就行了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+7;
    const int inf=0x3f3f3f3f;
    struct note{
        int to,nex;
    }e[maxn*3];
    int col,num,head[maxn],dfn[maxn],low[maxn],de[maxn],co[maxn],si[maxn],stk[maxn];
    int top,n,m;
    int cnt=-1;
    void add(int x,int y)
    {
        static int cnt=0;
        cnt++;
        e[cnt].to=y;
        e[cnt].nex=head[x];
        head[x]=cnt;
    }
    
    void tarjan(int u)
    {
        dfn[u]=low[u]=++num;
        stk[++top]=u;
        for(int i=head[u];i;i=e[i].nex)
        {
            int v=e[i].to;
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!co[v])low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            co[u]=++col;
            ++si[col];
            while(stk[top]!=u)
            {
                ++si[col];
                co[stk[top]]=col;
                --top;
            }
            --top;
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int x,y,f;
            cin>>x>>y>>f;
            if(f==1)add(x,y);
            if(f==2)add(x,y),add(y,x);
        }
        for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
        for(int i=1;i<=col;i++)cnt=max(cnt,si[i]);
        cout<<cnt<<endl;
        for(int i=1;i<=n;i++)
        {
            if(si[co[i]]==cnt)
            {
               int now=co[i]; 
               for(int j=i;j<=n;j++)if(co[j]==now)cout<<j<<" ";
               return 0; 
            }
        }
        return 0;
    }

    后记:裸的Tarjan题还是很好看出解法的,但是和其他图论算法结合起来就十分难受了,有时候真的是绞尽脑汁也想不出来。

  • 相关阅读:
    appium 3-4-1034等待、日志、性能数据、xpath定位、web driver协议
    appium 3-31626 toast识别
    appium 3-31603调试分析方法
    java-appium-527 WebDriver协议&针对控件的操作
    java-appium-527进阶-1 UiAutomator1&2区别和封装
    python-appium520-2初步使用
    python-appium520-3引入unittest,编写自动化用例
    Android手机卸载第三方应用
    grub名词理解
    基于ubuntu和windows连接
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12513988.html
Copyright © 2011-2022 走看看