很妙的一题
题意
给出\(n\)个节点\(m\)条边的无向连通图和参数\(k\),求:
- 严格\(\lceil \frac{k}{2} \rceil\)大小的点独立集
- 或大小$ k$的简单环
\(3 \leq k \leq n \leq 10^5,n-1 \leq m \leq 2 \cdot 10^5\)
思路
解法1
 我们求出一个原图的DFS树,当某个节点\(u\)存在反向边时,找出终点\(v\)深度最深的反向边.容易看出这个反向边在一个简单环中,且这个简单环不会被其他边分割.如果这个环的大小\(\leq k\),直接输出即可,否则我们取不相邻的\(\lceil \frac{k}{2} \rceil\)个点,它们形成一个点独立集.
 如果原图无环(或者说是一棵树),那么我们很容易就能求出大小\(\lceil \frac{k}{2} \rceil\)的点独立集.
解法2
 我们求出任意一个环,然后枚举所有的边\(1...m\).如果某条边把这个环分割开(即起点终点都在环上),那么保留这个环的任意一半,继续该过程.最后我们会得到一个不被其他边分割的简单环.之后的处理同解法1.
 如果原图是一棵树,同解法1.
 (比赛时我用的就是这种做法,但是写T了=-=个人觉得这是最难想也最难写的做法,鬼知道我当时在干什么)
解法3
 (来自Um_nik的代码)https://codeforces.com/contest/1364/submission/83636767
 %%%%%
 根据原题,无论我们求点独立集还是简单环,都需要最多\(k\)个点,那么我们简单粗暴地把所有编号$ > k\(的点删掉,再在剩下的图(**注意新图可能不连通**)中寻找环.如果我们找到任意一个环,直接输出即可,因为这个环的大小肯定\)k\(.如果没有环(新图是一个森林),那也能很容易地找到\) $大小的点独立集.
代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 
 | #include <bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 const int maxn = 4e5+10;
 const int maxm = 4e5+10;
 struct Edge{
 int from,to,next,cnt;
 Edge(int from = 0,int to = 0,int next = 0):from(from),to(to),next(next){}
 }edge[maxn];
 int head[maxn],cnt,d,dep[maxn],p[maxn];
 bool vis[maxn],col[maxn];
 void addedge(int f,int t){
 edge[cnt] = Edge(f,t,head[f]);
 head[f] = cnt++;
 }
 int n,m,k;
 void DFS(int u){
 if(vis[u])return;
 vis[u] = 1;
 for(int i = head[u];~i;i = edge[i].next){
 int v = edge[i].to;
 if(vis[v] and dep[v] > dep[u]){
 vector<int>cir = {};
 int cur = v;
 while(cur != u){
 cir.push_back(cur);
 cur = p[cur];
 }
 cir.push_back(u);
 int s = cir.size();
 cout << 2 << endl << s << endl;
 for(int yay:cir)cout << yay << " ";
 exit(0);
 }
 else if(!vis[v]){
 p[v] = u;
 dep[v] = dep[u]+1;
 col[v] = !col[u];
 DFS(v);
 }
 }
 }
 int main(){
 ios::sync_with_stdio(0);
 memset(head,-1,sizeof(head));
 cin >> n >> m >> k;
 d = ceil((double)k/2);
 for(int i = 1;i <= m;i++){
 int f1,t1;
 cin >> f1>> t1;
 if(f1 > k or t1 > k)continue;
 addedge(f1,t1);
 addedge(t1,f1);
 }
 int cnt1 = 0;
 for(int i = 1;i <= n;i++)DFS(i);
 vector<int>ans = {};
 for(int i = 1;i <= n;i++)if(col[i])cnt1++;
 int qwq = 0;
 if(cnt1 >= d)qwq = 1;
 for(int i = 1;i <= n;i++)if(col[i] == qwq){
 if((int)ans.size() == d)break;
 ans.push_back(i);
 }
 cout << 1 << endl;
 for(int x:ans)cout << x << " ";
 return 0;
 }
 
 |