思维dfs树/求最小环——cf 1364D

Posted zsben991126

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了思维dfs树/求最小环——cf 1364D相关的知识,希望对你有一定的参考价值。

这题的强化版 1325F

题目里很友好的给了一个结论:对于任何一张n个点的无向图,任何一个k<=n,图中要么有大小不超过k的环,要么有大小为ceil(k/2)的独立集

证明很简单:

  我们先定义单元环:环上的点的度数都为2

  对于任意一个单元环,其大小如果超过k,那么必有>=ceil(k/2)的独立集

然后考虑如何求任意一个这样的单元环:bfs时只要碰到的第一个环就是单元环,我们把这个单元环取出来判一下就行

/*
图中的最小环,如果环大小>k,说明环中必定存在ceil(k/2)的独立集 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 200005

int n,m,k,pre[N],vis[N];
vector<int>G[N],cir; 

void reverse(vector<int>&v){
    int i=0,j=v.size()-1;
    while(i<j)
        swap(v[i],v[j]),++i,--j;
}

void bfs(){
    for(int i=1;i<=n;i++)vis[i]=-1;
    queue<int>q;
    q.push(1);
    vis[1]=1;pre[1]=1;
    while(q.size()){
        int u=q.front();q.pop();
        for(auto v:G[u])if(v!=pre[u]){
            if(vis[v]==-1){
                vis[v]=vis[u]^1;
                q.push(v);
                pre[v]=u;
            }
            else {//出现环了 
                vector<int>v1,v2;
                int t=v;
                v1.push_back(t);
                while(pre[t]!=t)
                    v1.push_back(pre[t]),t=pre[t];
                t=u;
                v2.push_back(t);
                while(pre[t]!=t)
                    v2.push_back(pre[t]),t=pre[t];
                
                reverse(v1);
                reverse(v2);
                
                //for(auto x:v2)cout<<x<<" ";
                
                int i;
                vector<int>s;
                for(i=0;i<v1.size()&&i<v2.size();i++)
                    if(v1[i]!=v2[i])break;
                i--;
                for(int j=i;j<v1.size();j++)
                    s.push_back(v1[j]);
                for(int j=v2.size()-1;j>i;j--)
                    s.push_back(v2[j]);
                if(s.size()<=k){//环<=k 
                    cout<<2<<
<<s.size()<<
;
                    for(auto x:s)cout<<x<< ;
                    return;
                }
                
                vector<int>s1,s0;//独立集 
                for(auto x:s){
                    if(vis[x]==0)s0.push_back(x);
                    else s1.push_back(x);
                }                
                if(s1.size()>s0.size())swap(s1,s0);
                cout<<1<<"
";
                for(int i=0;i<ceil(1.0*k/2);i++)
                    cout<<s1[i]<<" ";
                return; 
            }
        }
    }
    //是个无环图输出独立集即可 
    vector<int>s1,s0;
    for(int x=1;x<=n;x++){
        if(vis[x]==0)s0.push_back(x);
        else s1.push_back(x);
    }
    if(s1.size()<s0.size())swap(s1,s0);
    cout<<1<<"
";
    for(int i=0;i<ceil(1.0*k/2);i++)
        cout<<s1[i]<<" ";
    return;      
}

int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++){
        int u,v;scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    bfs();
}

 

以上是关于思维dfs树/求最小环——cf 1364D的主要内容,如果未能解决你的问题,请参考以下文章

CF1364D Ehab‘s Last Corollary(思维,环,二分图,构造)

[CF609E]Minimum spanning tree for each edge

CF1325F Ehab's Last Theorem(dfs树找环与独立集)

CF1242B 0-1MST(思维)

代码源 Div1 - 109#454. Minimum Or Spanning Tree(最小生成树,边权按位或,贪心,并查集) CF1624G

代码源 Div1 - 109#454. Minimum Or Spanning Tree(最小生成树,边权按位或,贪心,并查集) CF1624G