题意

给定一张 nnn 个节点,mmm 条边的无向连通图。求输出一组节点覆盖,使得最多有一条边的两端节点都被选择。

  • 2≤n≤1062\le n\le 10^62≤n≤106
  • n−1≤m≤min⁡(106,n×(n−1)2)n-1\le m\le\min(10^6,\frac{n\times(n-1)}2)n−1≤m≤min(106,2n×(n−1)​)

思路

考虑所有边都只有一个端点被选的覆盖。如果存在这样一组覆盖,那么原图一定是二分图

接下来,考虑有一个边的两个端点都被选的情况。我们发现如果原图不是二分图,那么一定存在奇环。我们希望找到一条边,将这条边两个端点合并后,能使得原图变成二分图,就满足了题目。

所以这条边一定要存在于所有奇环上,且不能存在于任意偶环上(合并后要让奇环消失且不能产生新的奇环)。这样就想到在 dfs 进行二分图染色的同时统计所有的环,对每个边记录它存在的奇环和偶环数量。

统计时需要用到一个树上差分的小技巧。我们知道无向图 dfs 中除了树边就是回边,我们发现只要考虑由若干个树边和一个回边组成的环就可以了,其他的环一定是由这些环的边组成的。只要在发现环时,对回边记一次数,再对树边路径差分统计一下。最后总的 dfs 一次统计子树和,就能统计出每条边的奇环偶环个数。

然后我们就找到一条存在于所有奇环上的边,将其删除就能得到二分图。如果这条边不存在,输出 NO。最后进行一次二分图染色,注意要让被删边的端点染为 1。

实现时有一些细节要注意,例如要处理一下每个点在 dfs 上的父边。

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define mp make_pair
#define F first
#define S second
#define debug(x) cerr<<#x<<"="<<x<<endl
using namespace std;
inline int read(){//快读快写int x=0,f=0;char ch=getchar();while(!isdigit(ch))f|=ch=='-',ch=getchar();while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return f?-x:x;
}
template<typename T>inline void write(T x){if(x<0)x=-x,putchar('-');if(x>9)write(x/10);putchar(x%10^48);
}
int n,m,odd,cnt0[1000005],cnt1[1000005],c[1000005],fe[1000005];//cnt0偶环个数,cnt1奇环个数,c节点颜色,fe父边
bool vis[1000005];
pii e[1000005];
vector<pii> G[1000005];
void dfs(int u,int p,int cl)//二分图染色同时找环
{c[u]=cl;vis[u]=1;fe[u]=p;for(auto pp:G[u])if (pp.S!=p){int to=pp.F,id=pp.S;if (c[to]==-1)dfs(to,id,cl^1);else if (c[to]==cl^1&&vis[to])//偶环cnt0[id]++,cnt0[p]++,cnt0[fe[to]]--;else if (c[to]==cl&&vis[to])//奇环odd++,cnt1[id]++,cnt1[p]++,cnt1[fe[to]]--;}vis[u]=0;//回溯时撤销访问标记
}
void dfs2(int u)//整理差分数组,得到每条边的计数
{vis[u]=1;for(auto pp:G[u])if (!vis[pp.F]){int to=pp.F;dfs2(to);if (fe[u]!=-1&&fe[to]!=-1);cnt0[fe[u]]+=cnt0[fe[to]],cnt1[fe[u]]+=cnt1[fe[to]];}
}
void dfs3(int u,int cl)//二分图染色
{c[u]=cl;for(auto pp:G[u])if (c[pp.F]==-1){int to=pp.F;dfs3(to,cl^1);}
}
void run()
{odd=0;//一系列初始化n=read(),m=read();for(int i=0;i<n;i++)G[i].clear();fill(cnt0,cnt0+m+3,0);fill(cnt1,cnt1+m+3,0);fill(c,c+n+3,-1);fill(vis,vis+n+3,0);for(int i=0;i<m;i++){e[i]=mp(read()-1,read()-1); G[e[i].F].pb(mp(e[i].S,i));G[e[i].S].pb(mp(e[i].F,i));}dfs(0,-1,0);fill(vis,vis+n+3,0);dfs2(0);int x=-1,y=-1;if (odd)//存在奇环{for(int i=0;i<m&&x==-1;i++)if (cnt1[i]==odd&&cnt0[i]==0)x=i;if (x==-1){puts("NO");return;}y=e[x].F,x=e[x].S;sort(G[x].begin(),G[x].end());sort(G[y].begin(),G[y].end());G[y].erase(lower_bound(G[y].begin(),G[y].end(),mp(x,-1)));//删边G[x].erase(lower_bound(G[x].begin(),G[x].end(),mp(y,-1)));}fill(c,c+n+3,-1);dfs3(0,1);int f=(x==-1?0:c[x]^1);//保证被删边的端点颜色为1puts("YES");for(int i=0;i<n;i++)write(c[i]^f);putchar('\n');
}
int main()
{int TT=read();while(TT--)run();return 0;
}
  • 时间复杂度:O⁡(n+m)\operatorname O(n+m)O(n+m)
  • 空间复杂度:O⁡(n+m)\operatorname O(n+m)O(n+m)

我的程序又臭又长(

CF1680F Lenient Vertex Cover题解相关推荐

  1. PAT甲级1134 Vertex Cover :[C++题解]顶点覆盖、图论、用结构体存边,bool数组判断

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析:首先把所有的边存储下来,使用结构体,结构体中保存两个端点. 然后对于每次询问,将出现过的顶点标志为true放在st数组中,然后遍历所有 ...

  2. 1134. Vertex Cover (25)

    1134. Vertex Cover (25) 时间限制 600 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A vertex ...

  3. 集合覆盖 顶点覆盖: set cover和vertex cover

    这里将讲解一下npc问题中set cover和vertex cover分别是什么. set cover: 问题定义: 实例:现在有一个集合A,其中包含了m个元素(注意,集合是无序的,并且包含的元素也是 ...

  4. 二分图匹配 + 最小点覆盖 - Vertex Cover

    Vertex Cover Problem's Link Mean: 给你一个无向图,让你给图中的结点染色,使得:每条边的两个顶点至少有一个顶点被染色.求最少的染色顶点数. analyse: 裸的最小点 ...

  5. 从顶点覆盖(Vertex Cover)到碰撞集(Hitting Set)的归约

    碰撞集问题 给定一组集合{S1,S2,S3,-,Sn}和预算b,问是否存在一个集合H,其大小不超过b,且H和所有Si(i=1, 2, -, n)相交. 顶点覆盖问题 给定图G,问是否存在一个顶点集合V ...

  6. Vertex Cover问题

    最近算法课上完成了一道作业题,Vertex Cover,拿出来与大家分享一下.算法不能说有多好,有问题欢迎致信ms08.shiroh@gmail.com 1,问题描述 首先Vertex Cover问题 ...

  7. 【题解】Luogu SP1435 PT07X - Vertex Cover

    原题传送门 求树的最小点覆盖,就是一个树形dp 类似于没有上司的舞会 dp的状态为\(f[i][0/1]\),表示i节点是否选择 边界是\(f[x][0]=0\),\(f[x][1]=1\) 转移方程 ...

  8. SCU 4439 Vertex Cover(二分图最小覆盖点)题解

    题意:每一条边至少有一个端点要涂颜色,问最少涂几个点 思路:最小顶点覆盖:用最少的点,让每条边都至少和其中一个点关联,显然是道裸最小顶点覆盖题: 参考:二分图 代码: #include<iost ...

  9. Gym 100431E Word Cover 题解:KMP上跑dp

    题意: 给你一个串,问你他的每个前缀的最小重复单元,其中单元是可以重叠的,最后按顺序输出即可.比如样例中abaabaa的最小重复单元为abaa,所以相应输出为4. 样例: input : abaaba ...

  10. HDU-6150 Vertex Cover(构造)

    传送门:HDU-6150 网络赛的时候不知道哪根筋搭错了,硬是想不出来,感觉一道全世界都会写的题目,自己就是写不出(导致挂机2个半小时)好想进第一页啊TAT 题意:有一个贪心算法求最小顶点覆盖是每次选 ...

最新文章

  1. 物理虚拟化服务器之间的KVM在线动态迁移
  2. C++继承机制下的析构函数
  3. linux如何判断网线插入_斜口钳和网线钳制作网线!
  4. 自定义预览_为什么NVR预览画面数量少于已经添加的通道数
  5. 米其林全球挑战赛电子门票欣赏
  6. spring mvc 异步_DeferredResult – Spring MVC中的异步处理
  7. 调整手机titlebar与app的titlebar相衔接
  8. tensorflow随笔——VGG网络
  9. MySQL--当事务遇到DDL命令
  10. 软件测试简历常见问题
  11. JAVA基础算法(6)----- 国际象棋 α 皇后问题
  12. 关于Windows无法访问指定设备路径或文件,您可能没有合适的权限访问问题解决转
  13. 京东HBase平台进化与演进
  14. JavaScript实战——打气球游戏
  15. fir.im Weekly - 揭秘直播移动 APP 技术实现
  16. 全球与中国家庭捕鱼船市场深度研究分析报告
  17. 62 stm32 usb自定义hid复合设备修改实验
  18. 从聚焦沉淀到探索创新,跨境支付正在酝酿下一个行业浪潮
  19. python中函数的作用不包括_Python 列表不包含了以下哪个内置函数( )_财经法规答案_学小易找答案...
  20. 重温经典(三)-百年思索

热门文章

  1. 菜狗杯Misc迅疾响应wp
  2. 拉文大学计算机科学,美国研究生语言双录取,这些大学有你中意的吗?
  3. 一款开源好用的车辆管理系统源码,基于SSH框架和SaaS模式
  4. 阿里P9纯手打亿级高并发系统设计手册,走进阿里的架构世界
  5. 路由器功能及构成——网络层
  6. octet和byte的差异
  7. 4.各种动物英语表示
  8. CSDN,hen hao,hen qiang da
  9. 两个不同包里有相同的类
  10. 哪款视频压缩软件比较好用?