码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-06-15 22:52:02      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:第一个   amp   namespace   style   存在   scanf   include   pop   while   

这题的强化版 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<<\n<<s.size()<<\n;
                    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<<"\n";
                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<<"\n";
    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

标签:第一个   amp   namespace   style   存在   scanf   include   pop   while   

原文地址:https://www.cnblogs.com/zsben991126/p/13138191.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!