模拟赛 妖怪等级考试 题解

妖怪等级考试:

给定一个无向连通图,求是否存在两个点之间存在三条路径,
并要求输出路径。
首先,如果两个节点之间存在多条不相交路径,就一定存在一个环。
所以,这题和找环相关。
只有两个环之间存在相交的边,才说明有解。
如图:

现在关键就是如何找到环。
由于无向图dfs后,只有树边和返祖边,且只有返祖边才会形成环,所以只要对返祖边处理就可以了。
每次将第个\(i\)环上所有边染成\(i\)色,当有一个边被染成两种颜色时,就找到了解。
因为每条边最多被染一次就会出现解,所以染色可以暴力进行。
如图:

输出解时考虑三种情况就可以了。

#include <stdio.h>
int fr[100010],ne[400010];
int v[400010],bs=0,fa[100010];
bool fz[400010];
int hu[400010],fb[100010];
int h2,x[400010],dfn[100010],tm=0;
int sd[100010],jg[100010];
void addb(int a,int b)
{
    x[bs]=a;
    v[bs]=b;
    ne[bs]=fr[a];
    fr[a]=bs;
    hu[bs]=-1;
    bs+=1;
}
int dfs(int u,int f)
{
    sd[u]=sd[f]+1;
    fa[u]=f;
    tm+=1;
    dfn[u]=tm;
    for(int i=fr[u];i!=-1;i=ne[i])
    {
        if(v[i]==f)
            continue;
        if(dfn[v[i]]==0)
        {
            fb[v[i]]=i;
            int t=dfs(v[i],u);
            if(t!=-1)
                return t;
        }
        else if(dfn[v[i]]<dfn[u])
        {
            int t=u;
            while(t!=v[i])
            {
                if(hu[fb[t]]!=-1)
                {
                    h2=i;
                    return fb[t];
                }
                hu[fb[t]]=i;
                t=fa[t];
            }
        }
    }
    return -1;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        fr[i]=-1;
    for(int i=0;i<m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        addb(a,b);
        addb(b,a);
    }
    int rt=dfs(1,-1);
    if(rt==-1)
        printf("NO");
    else
    {
        printf("YES\n");
        int t=v[hu[rt]];
        if(sd[v[h2]]>sd[t])
            t=v[h2];
        int z=v[rt],s=0;
        while(1)
        {
            s+=1;
            if(z==t)
                break;
            z=fa[z];
        }
        printf("%d ",s);
        z=v[rt];
        while(1)
        {
            printf("%d ",z);
            if(z==t)
                break;
            z=fa[z];
        }
        printf("\n");
        int a1=v[h2],a2=v[hu[rt]];
        z=t,s=0;
        while(1)
        {
            jg[s]=z;
            s+=1;
            if(z==a1)
                break;
            z=fa[z];
        }
        z=x[h2];
        while(1)
        {
            jg[s]=z;
            s+=1;
            if(z==v[rt])
                break;
            z=fa[z];
        }
        printf("%d ",s);
        for(int i=s-1;i>=0;i--)
            printf("%d ",jg[i]);
        printf("\n");
        z=t,s=0;
        while(1)
        {
            jg[s]=z;
            s+=1;
            if(z==a2)
                break;
            z=fa[z];
        }
        z=x[hu[rt]];
        while(1)
        {
            jg[s]=z;
            s+=1;
            if(z==v[rt])
                break;
            z=fa[z];
        }
        printf("%d ",s);
        for(int i=s-1;i>=0;i--)
            printf("%d ",jg[i]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lnzwz/p/11246711.html

时间: 2024-10-08 08:54:19

模拟赛 妖怪等级考试 题解的相关文章

一个被不点名批评的垃圾骗分暴力选手被普及难度的省选信心(??)模拟赛艹爆的题解

如果真是这种实力去什么省选啊,浪费钱浪费名额浪费时间,不如退役充当编程爱好者打网站,回去搞课内弃理从文刷刷计算题好歹成绩还好看一点 精神状态很好,也没有任何不适,几乎在正常考试都保持了挺高的精神集中,这样都垫底真是f**k ---------考场上的废柴发挥----------- 昨晚见到OZY,得知输出样例有分不会爆零太好了心情极佳,然而题怎么******* (自从那天开始满脑子都是暴力骗分的yzh) 早上先看了半个小时题目,感觉t1就是签到找规律,t2一眼暴力+KM40分美滋滋,正解怕是在t

【noip模拟赛 化零】 题解

Describe 有5个集合,每个集合N个元素,从每个集合选出一个数,共5个,问是否可以使和为0. IN put: 第一行一个整数 N,表示集合的大小. 接下来五行每行 N个整数,表示这五个集合内的元素. OUT put: 如果能找到符合条件的五个数,则输出"YES",否则输出"NO". example: in 3 1 -2 9 -1 2 1 -3 5 1 -1 7 6 -4 -1 -7 out YES 数据范围: N<=20 30% N<=200 10

模拟赛 10-25上午考试记

10-25上午考试记 NP(np) Time Limit:1000ms Memory Limit:64MB 题目描述 LYK 喜欢研究一些比较困难的问题,比如 np 问题. 这次它又遇到一个棘手的 np 问题.问题是这个样子的:有两个数 n 和 p,求 n 的阶乘 对 p 取模后的结果. LYK 觉得所有 np 问题都是没有多项式复杂度的算法的,所以它打算求助即将要参加 noip 的你,帮帮 LYK 吧! 打表发现如果n>=p,答案就是0. 所以把n的范围缩小到1e7.但是有p=1e9+7. 分

WC2019 全国模拟赛第一场 T1 题解

由于只会T1,没法写游记,只好来写题解了... 题目链接 题目大意 给你一个数列,每次可以任取两个不相交的区间,取一次的贡献是这两个区间里所有数的最小值,求所有取法的贡献和,对 \(10^9+7\) 取模. 数列长度 \(2\times 10^5\) ,值域 \(1\) ~ \(10^9\) . \(O(n^4)\) 做法 预处理区间最小值,枚举选的两个区间. #include <iostream> #include <cstdio> #include <algorithm&

【题解】PAT团体程序设计天梯赛 - 模拟赛

由于本人愚笨,最后一题实在无力AC,于是只有前14题的题解Orz 总的来说,这次模拟赛的题目不算难,前14题基本上一眼就有思路,但是某些题写起来确实不太容易,编码复杂度有点高~ L1-1 N个数求和 设计一个分数类,重载加法运算符,注意要约分,用欧几里得算法求个最大公约数即可. 1 #include <cstdio> 2 3 long long abs(long long x) 4 { 5 return x < 0 ? -x : x; 6 } 7 8 long long gcd(long

10-4国庆节第七场模拟赛题解

10-4 国庆节第七场模拟赛题解 T1工厂 (factory) 水 #include<iostream> #include<cstdio> #define int long long using namespace std; inline int read(){ int sum=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); } while(ch>='0

lzoi模拟赛题解

A题:签到题原题:mtoi 联赛 的A题定位:真.签到题(普及B题或者提高d1A题)考点:选手的基本数学能力思维难度:提高-代码难度:普及A题 题解:80%:暴力枚举100%:注意到(a xor b)<=(a+b),于是把所有的数异或起来即可. B题:送分题原题:[多省省队联测]d2A:皮配定位:一道联赛d1B题,考察了选手的基本功.送了选手70分.把70%的2种做法扩展可以得到正解考点:多种背包dp,计数思维难度:提高代码难度:提高+ 前面的几个数据可以暴力枚举解决.50%的数据:考虑dp.设

计蒜课 八月模拟赛题解

看见机房有大佬上周写了上面的普及信心赛 于是我康了康 8月的提高组模拟赛 9月的还没开始qwq 真的 有点难 主要是我先打开了T2 我再次 对自己的数学产生了怀疑 我现在还是不会写T2 T1 又又又又都错题了 下次重建图 尽量写vector 都写 邻接表 变量差不多的容易搞混 我这个同学变又写错了 T1 :https://nanti.jisuanke.com/t/41086 题目大意就是 一个有向图 删一个点 把与他直接和间接 相连的点 删掉 然后 求删掉所有点的最小最大代价 : 为了避免这个环

10月15日模拟赛题解

10月15日模拟赛题解 A 树 Description 给定一棵 \(n\) 个节点的树,每个节点有两个参数 \(a,~b\),对于每个节点,求子树中参数为 \(b\) 的所有节点的 \(a\) 之和 Limitations \(100\%\) \(1 \leq b \leq n \leq 10^5,~a \leq 1000\) \(60\%\) \(1 \leq b,n\leq 1000\) \(30\%\) \(1 \leq b, n \leq 10\) Solution 对于 \(30\%