首页 > 其他分享 >CF1818D 题解

CF1818D 题解

时间:2023-06-05 09:23:24浏览次数:48  
标签:cnt 环上 int 题解 u1 v1 CF1818D 节点

一、题目描述:

  给你一颗 $n$ 个点,$m$ 条边的简单无向图,可能不连通。

  我们定义 $鱼图$ 为满足以下条件的无向图:

    $包含恰好\ 1\ 个环,环上有\ 1\ 个特殊的结点\ u\ ,u\ 除了连在环上的\ 2\ 条边外还正好有\ 2\ 条边连向不在此环上的结点。$

  求是否存 $鱼图$。若存在,输出 $YES$ 和这个鱼图。若不存在,输出 $NO$。数据范围 $1\leq n,m\leq 2\times 10^3$。


 二、解题思路:

  我们考虑找到上述 $特殊的节点$ 。

  发现这个节点只要在环中,并且只要有 $4$ 条边就行了。

  边数好判断,怎么判断一个点是否在环中呢?

  $sb-yhy$ 告诉我们,可以用拓扑排序判环。

  是的,我们确实可以用拓扑排序判环,于是我就寄了。

  给大家看这样一个图:

  

  这个神奇的 $4$ 号节点其实不在环上,但是却不会被判出来。

  所以,可以使用拓扑排序判断是否有环,但不能使用拓扑排序判断一个点是否在环上。

  那该如何判断呢?考虑 $dfs$ 找环,于是我就又寄了。

  给大家看这样一个图:

  

  在这个图中,如果我们找到的环是 $4-1-3-2-4$,你就会发现 $4$ 号节点只剩下一条边没有连在环上,满足不了 $鱼图$ 的条件了。

  所以我们要找最小图。于是请 $bfs$ 登场。

  记录下前驱,如果搜到已经搜过的点,那么环就找到了,于是我又寄了。

  回到最上面那个图: 

  

  我们会搜索到 $2$ 号和 $3$ 号节点相连,但 $4$ 号节点仍然不在环中。

  所以我 $很聪明的$ 去看了题解,得到了 $Alex\_wei$ 的启发:

    $记录下每个节点是从原点的哪一个邻接点出来的,记为\ top_i。如果\ top_i\ 不一样,则找到了环。$

  于是我终于 $顺利$ 地过掉了这个题。时间复杂度 $O(n \times m)$。


 三、完整代码:

 1 #include<iostream>
 2 #define N 2010
 3 #define to edge[i].v
 4 using namespace std;
 5 int T,n,m,x,u1,v1,cc,l,r;
 6 int h[N],q[N],f[N],d[N],du[N],tp[N],vis[N],pre[N];
 7 struct EDGE{
 8     int v,nxt;
 9 }edge[N*2];
10 int head[N],cnt;
11 void add(int u,int v)
12 {
13     edge[++cnt].v=v;
14     edge[cnt].nxt=head[u];
15     head[u]=cnt;
16 }
17 void print(int s,int u,int v)
18 {
19     for(int i=1;i<=n;i++)f[i]=0;
20     x=u;while(x!=s)f[x]=1,x=pre[x],cc++;
21     x=v;while(x!=s)f[x]=1,x=pre[x],cc++;
22     cout<<"Yes"<<'\n'<<cc<<'\n';
23     x=u;while(x!=s)
24         cout<<x<<" "<<pre[x]<<'\n',x=pre[x],cc--;
25     x=v;while(x!=s)
26         cout<<x<<" "<<pre[x]<<'\n',x=pre[x],cc--;
27     cout<<u<<" "<<v<<'\n',cc--;
28     for(int i=head[s];i!=-1;i=edge[i].nxt)
29         if(!f[to]&&cc)    cout<<s<<" "<<to<<'\n',cc--;
30 }
31 int Try(int u)
32 {
33     l=r=0;
34     for(int i=1;i<=n;i++)    f[i]=0;
35     for(int i=head[u];i!=-1;i=edge[i].nxt)
36         q[++r]=to,pre[to]=u,f[to]=1,tp[to]=to;
37     while(l<r)
38     {
39         int x=q[++l];
40         for(int i=head[x];i!=-1;i=edge[i].nxt)
41             if(pre[x]!=to&&!vis[x])
42             {
43                 if(!f[to])q[++r]=to,f[to]=1,pre[to]=x,tp[to]=tp[x];
44                 else if(tp[x]!=tp[to]) {print(u,x,to);return 1;}
45             }
46     }
47     return 0;
48 }
49 void top_sort()
50 {
51     l=r=0;
52     for(int i=1;i<=n;i++)
53         d[i]=du[i];
54     for(int i=1;i<=n;i++)
55         if(du[i]==1)
56             q[++r]=i,vis[i]=1;
57     while(l<r)
58     {
59         int u=q[++l];
60         for(int i=head[u];i!=-1;i=edge[i].nxt)
61         {
62             du[to]--;
63             if(!vis[to]&&du[to]<2)
64                 q[++r]=to,vis[to]=1;
65         }
66     }
67     for(int i=1;i<=n;i++)
68         du[i]=d[i];
69 }
70 void solve()
71 {
72     cin>>n>>m;cnt=0;cc=3;
73     for(int i=1;i<=n;i++)
74         head[i]=-1,f[i]=du[i]=vis[i]=0;
75     for(int i=1;i<=m;i++)
76     {
77         cin>>u1>>v1;
78         add(u1,v1),du[u1]++;
79         add(v1,u1),du[v1]++;
80     }
81     top_sort();
82     for(int i=1;i<=n;i++)
83         if(du[i]>=4&&!vis[i])
84             if(Try(i))    return ;
85     cout<<"NO"<<'\n';
86 }
87 int main()
88 {
89     ios::sync_with_stdio(false);
90     cin.tie(0);cout.tie(0);
91     cin>>T;
92     for(int i=1;i<=T;i++)
93         solve();
94     return 0;
95 }

四、写题心得:

  原来我的图论板块还有这么多漏洞,还得好好学啊。加油!拜拜!

标签:cnt,环上,int,题解,u1,v1,CF1818D,节点
From: https://www.cnblogs.com/yhy-trh/p/CF1818D.html

相关文章

  • 题解
    原题请见题目链接1.暴力求解这是我们线下水题赛的T1这里为初学者提供一个思路,假设我们现在刚入OI,在考场上如何怎么优雅的避免保灵显然我们只要用一个\(O(n)\)的暴力去扫描就行了,但是直接向后扫\(i+1,i+2\)这样走很容易寄。因为你在\(i+1\)跳的时候很容易把后面跳过了......
  • 【题解】[ABC304F] Shift Table(容斥)
    【题解】[ABC304F]ShiftTable题目链接ABC304F题意概述Takahashi和Aoki将在接下来的\(N\)天里兼职工作。Takahashi这\(n\)天的出勤情况由字符串\(S\)表示,其中\(S\)的第\(i\)个字符是#则表示他在第\(i\)天工作,第\(i\)个字符是.表示他在第\(i\)天休息......
  • 题解:【AGC054D】 (ox)
    题目链接Larry76牛牛首先考虑没有ox怎么做,就是将括号序列调成合法。\(|S|\)不大直接模拟一遍,记录\(now\)表示一个前缀权值,当遇到一个(时\(+1\),遇到一个)时\(-1\),当\(now<0\)的时候说明序列不合法即)多了,暴力向后找到第一个(交换到当前的)前面。这样我们......
  • Codeforces Round 876 (Div. 2)题解
    CodeforcesRound876(Div.2)A.TheGoodArray标签greedymath题意对于任意\(i\in\{1,2,\dots,n\}\),要求数列\(a\)满足前\(i\)个元素中至少有\(\lceil\frac{i}{k}\rceil\)个元素为\(1\),后\(i\)个元素中至少有\(\lceil\frac{i}{k}\rceil\)个元素为\(1\)。思......
  • “AIR SDK 0.0: AIR SDK location “...\devsdks\AIRSDK\Win” does not exist.”
    导入AS3项目时提示“AIRSDK0.0:AIRSDKlocation“D:\ProgramFiles\Adob5eFlashBuilder4.7\eclipse\plugins\com.adobe.flexbuilder.flex_4.7.0.349722\devsdks\AIRSDK\Win”doesnotexist.”是AS3项目找不见AIRSDK.打开项目配置ActionScriptBuildPath,路径出错......
  • CF1329E Dreamoon Loves AA 题解
    令\(p_0=0,m\leftarrowm+1,p_{m}=n,a_i=p_i-p_{i-1}\),设在\((p_{i-1},p_i)\)中有\(d_i-1\)个B变成了A,满足\(\sum_{i=1}^m(d_i-1)=k\),让\(k\leftarrowk+m\),这样\(d\)需要满足的限制就变成了\(\sum_{i=1}^md_i=k\)。这也可以看作把\(a_i\)分成\(d_i\)个正整数之......
  • ABC302Ex Ball Collector 题解
    注意到当有那些\((a_i,b_i)\)是确定的时,答案就是将\((a_i,b_i)\)连边后每个连通块的\(\min(|V|,|E|)\)之和。那么这个东西用可撤销并查集维护即可。#include<algorithm>#include<cstdio>usingnamespacestd;constintN=2e5;structEdge{intto,nxt;}e[......
  • 2023青岛市程序设计竞赛小学组题解
    1.付钱题目链接:https://www.luogu.com.cn/problem/U303904代码:#include<bits/stdc++.h>#definelllonglongusingnamespacestd;intmain(){ lln;cin>>n; cout<<n/100<<''<<(n%100)/50<<''<<(n%50)/20......
  • 第十届蓝桥杯c++b组国赛题解(还在持续更新中...)
    试题A:平方序列解题思路:直接枚举一遍x的取值,然后按照题目给定的式子算出y,每次取x+y的最小值即可答案为7020代码实现:#include<iostream>#include<algorithm>#include<cmath>usingnamespacestd;#defineintlonglongconstintN=1e4+5;signedmain(){ //记录答案......
  • ABC215E 题解
    前言题目传送门!更好的阅读体验?萌萌DP题。思路题目就是在说从\(a\)里面按顺序掏出来一些字母,使得相同的字母都是相邻的(比如AABBBBCD可行,AAABBCAA不行)。看起来很不可做,突破口在于\(\text{A}\sim\text{J}\)一共只有\(10\)个字母,考虑状压。设\(dp_{i,s}\)表示......