2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest G.Grand Test (Gym 101612G) 题解

2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest G.Grand Test 题解

题目链接

Gym 101612G

题意

在一个图中找两个点,使这两个点之间有三条不相交路径,并输出这三条路径。

题解

使用tarjan算法的思想,设dfn[x]为点x的访问时间顺序,low1[x]为x能到达的最小时序,end1[x]为x到达最小时序的路径的末端节点,low2[x]为x能到达的次小时序,end2[x]为x能到达次小时序的路径的末端节点,如果点x有两条路径能到达时序比它小的节点,即low2[x]<dfn[x],则x到low2[x]这个点之间存在三条不相交路径。

代码

#include <bits/stdc++.h>
using namespace std;
#define N 100010
int head[N],to[N*2],pre[N*2],fa[N],dfn[N],low1[N],low2[N],end1[N],end2[N],node[N];
int n,m,e,cnt;
bool flag;
vector<int> path;
void addedge(int x,int y)
{
    to[e]=y;pre[e]=head[x];head[x]=e++;
}
void init()
{
    for(int i=1;i<=n;++i) 
    {
        head[i]=-1;dfn[i]=0;
    }
    e=cnt=0;
}
void update(int x,int d,int y)
{
    if(d<low1[x])
    {
        low2[x]=low1[x];end2[x]=end1[x];
        low1[x]=d;end1[x]=y;
    }
    else if(d<low2[x])
    {
        low2[x]=d;end2[x]=y;
    }
}
void get_path(int s,int t,bool rev)
{
    vector<int> vec;
    for(int i=s;i!=t;i=fa[i]) vec.push_back(i);
    vec.push_back(t);
    if(rev) reverse(vec.begin(),vec.end());
    for(int x:vec) path.push_back(x);
}
void print_path()
{
    printf("%d ",path.size());
    for(int x:path) printf("%d ",x);
    printf("\n");
}
void tarjan(int x,int p)
{
    dfn[x]=low1[x]=low2[x]=++cnt;
    node[cnt]=x;end1[x]=end2[x]=x;
    for(int i=head[x];i!=-1;i=pre[i])
    {
        int y=to[i];
        if(y==p) continue;
        if(!dfn[y])
        {
            fa[y]=x;
            tarjan(y,x);
            update(x,low1[y],end1[y]);
        }
        else if(dfn[y]<dfn[x])
            update(x,dfn[y],x);
    }
    if(!flag&&low2[x]<dfn[x])
    {
        int s=x,t=node[low2[x]];
        printf("%d %d\n",s,t);

        path.clear();
        get_path(s,t,false);
        print_path();
        
        path.clear();
        get_path(end2[x],s,true);
        path.push_back(t);
        print_path();

        path.clear();
        get_path(end1[x],s,true);
        get_path(t,node[low1[x]],true);
        print_path();

        flag=true;
    }
}
int main()
{
    freopen("grand.in","r",stdin);
    freopen("grand.out","w",stdout);
    int ca,x,y;
    scanf("%d",&ca);
    while(ca--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d",&x,&y);
            addedge(x,y);addedge(y,x);
        }
        flag=false;
        for(int i=1;i<=n;++i)
            if(!dfn[i]) tarjan(i,-1);
        if(!flag) puts("-1");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值