1 条题解
-
0
自动搬运
来自洛谷,原作者为

Shikita
**搬运于
2025-08-24 21:53:24,当前版本为作者最后更新于2019-03-18 21:17:53,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
弦图 完美消除序列
弦图的前置知识
诱导子图:子图中任意一条边的两个端点一定也都在这个子图中
最大团:团中任意两点之间一定都有边,而包含顶点最多的团就是最大团
最小团覆盖:用最少的团覆盖图中所有的点
最大独立集:独立集中任意两点之间一定都没有边,而包含顶点最多的独立集就是最大独立集
最小染色:用最少的颜色给图染色使得图中任意相邻的两点颜色不相同
弦图:无向图中任意长度大于3的环都至少有一个弦,所谓弦就是连接环中不相邻两点的边
一般来讲:
①最大团数<=最小染色数
②最大独立集<=最小团覆盖
对于弦图来讲:
①最大团数==最小染色数
②最大独立集==最小团覆盖
单纯点:如果与顶点V相邻的所有点能构成一个团,那么V就是个单纯点
③任何一个弦图都有至少一个单纯点,不是完全图的弦图至少有两个不相邻的单纯点
完美消除序列:一个点的序列(每个点刚好出现1次)满足在诱导子图{}中为一个单纯点
一个无向图是弦图的充要条件是存在完美消除序列
再看本题的题意,题目中的数据保证M对矛盾所构成的图中不会有超过3个点的环
显然符合弦图的定义嘛
而题目中要求的矛盾关系,就是不能选择相邻的两个点嘛
妥妥的弦图最大独立集
做法
对于这种题目,我们只需要求个完美消除序列就好了,然后在完美消除序列上从前往后贪心取点即可
对于完美消除序列的求取方法
从后往前确定序列的点,每取一个点都把还没加入序列的和它相连的点的标号+1,每次取点选择标号最大的点之一,这样我们便可以求出一个完美消除序列
复杂度
接下去在完美消除序列上跑个贪心就好了
#include<bits/stdc++.h> using namespace std; inline int read() { int x=0; char c=getchar(); bool flag=0; while(c<'0'||c>'9') {if(c=='-')flag=1;c=getchar();} while(c>='0'&&c<='9'){x=(x+(x<<2)<<1)+ c-'0';c=getchar();} return flag?-x:x; } const int N=1e5+5; int n,m,vis[N],seq[N],num[N],id=1,ans; int to[N],nxt[N],head[N],cnt; vector<int>cg[N]; void add(int u,int cg){to[++cnt]=cg;nxt[cnt]=head[u];head[u]=cnt;} int main() { n=read();m=read(); for(int i=1;i<=m;++i) { int u=read(),v=read(); add(u,v),add(v,u); } for(int i=1;i<=n;++i) cg[0].push_back(i); for(int i=1;i<=n;++i) { int fg=0,now; while(!fg) { for(int j=cg[id].size()-1;j>=0;--j) if (!vis[cg[id][j]]) {fg=1;now=cg[id][j];break;} else cg[id].pop_back(); if(!fg) --id; } seq[i]=now;vis[now]=1; for (int e=head[now];e;e=nxt[e]) if (!vis[to[e]]) { cg[++num[to[e]]].push_back(to[e]); id=max(id,num[to[e]]); } } memset(vis,0,sizeof(vis)); for(int i=n;i;--i) if(!vis[seq[i]]) { ++ans;vis[seq[i]]=1; for(int e=head[seq[i]];e;e=nxt[e]) vis[to[e]]=1; } printf("%d\n",ans); }
- 1
信息
- ID
- 2789
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者