CF1364D Ehab 最后的结果

1 CF1364D Ehab 最后的结果

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

给定一个有 \(n\) 个顶点的连通的无向图和一个整数 \(k\),你必须进行下面某个操作:

  • 找出一个具有严格 \(\left\lceil\frac{k}{2}\right\rceil\) 个节点的独立集。
  • 找到一个长度最多为 \(k\) 的简单环。

独立集是没有任何两个节点通过边连接这一起的定点集合。一个简单环就是不包含更小的环的环。所有给出的数据都至少能够完成上面的某一个操作。

数据范围:\(3≤𝑘≤𝑛≤10^5, 𝑛−1≤𝑚≤2\times 10^5\)

3 题解

我们首先考虑为何两个条件必定满足至少一个。首先,如果一个图不满足第二个条件,即存在至少一个长度小于等于 \(k\) 的环,那么这个图要么没有环,要么最小环的长度大于 \(k\)。对于没有环的图来说,其一定是一棵树,而树都是二分图。所以此时整棵树一定可以通过染色将所有节点分为白色和黑色,且白色与黑色不相邻。我们只需要找到白色和黑色中最多的一个,然后去掉若干个(也可以不去)使得节点个数变为 \(\lceil \dfrac{k}{2} \rceil\)。对于长度大于 \(k\) 的环,设其长度为 \(x\),我们可以在环上隔一个点选一个点,这样我们能选出的肯定是独立集中的节点个数就是 \(\lfloor \dfrac{x}{2} \rfloor\)。此时 \(x\) 的最小值就是 \(k+1\),而 \(\lfloor \dfrac{k+1}{2} \rfloor\) 正好就是 \(\lceil \dfrac{k}{2} \rceil\)

根据我们上面的证明,我们可以想出这道题的做法:搜出图上的任意一个简单环。这里简单环的定义就是不包含更小环的任意大小的环。找出该环后,如果这个环的长度小于等于 \(k\),那么我们直接输出这个环。否则,我们可以隔一个节点输出一个节点,一共输出有 \(\lceil \dfrac{k}{2} \rceil\) 个节点,这些点一定组成一个独立集。而如果我们找不出任意一个环,或者说这个图是一棵树,那么我们就可以利用 \(dfs\) 将整棵树进行染色,然后计算白色和黑色的节点的个数分别是多少。如果某种颜色的节点个数大于等于另外一种颜色的节点的个数,那么该种节点的个数一定 \(\ge \lceil \dfrac{n}{2} \rceil\)。由于 \(k\) 小于等于 \(n\),所以这种节点的个数一定 \(\ge \lceil \dfrac{k}{2} \rceil\)。此时任意输出 \(\lceil \dfrac{k}{2} \rceil\) 个这种节点就可以构成满足题目的最大独立集了。

在代码实现上,我们可以先找出一个环,然后用 \(tail\) 记录环中上一个节点的编号。接下来遍历所有边,如果这条边不在环上且这条边连接的两个节点在环上,那么我们可以减去这两个节点之间的两条路径上的任意一条,缩小当前这个环的长度。便利结束之后,我们得到的环就是一个简单环。其余的操作按照上述的方法模拟即可。

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 1e5+10;
const int M = 2e5+10;
#define int long long
int n, m, k, tot, f, f2, top, st, lst, cnt;
int u[M], v[M], tail[N], co[N];
int head[N], ver[2*M], last[2*M];
int Q[N];
bool vis[N], vis2[N];
void add(int x, int y)
{
    ver[++tot] = y;
    last[tot] = head[x];
    head[x] = tot;
}
int dfs1(int x, int fa)
{
    Q[++top] = x;
    if (vis[x]) return 1;
    vis[x] = 1;
    for (int i = head[x]; i; i = last[i])
    {
        int y = ver[i];
        if (y == fa) continue;
        f2 = dfs1(y, x);
        if (f2) return f2;
    }
    top--;
    vis[x] = 0;
    return 0;
}
void dfs2(int x, int fa, int color)
{
    co[x] = color;
    for (int i = head[x]; i; i = last[i])
    {
        int y = ver[i];
        if (y == fa) continue;
        dfs2(y, x, color^1);
    }
}
signed main()
{
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++)
    {
        cin >> u[i] >> v[i];
        add(u[i], v[i]);
        add(v[i], u[i]);
    }
    f = dfs1(1, -1);
    if (!f)
    {
        dfs2(1, -1, 1);
        k = (k+1)/2;
        for (int i = 1; i <= n; i++) if (co[i]) cnt++;
        if (cnt >= k)
        {
            cnt = 0;
            cout << 1 << endl;
            for (int i = 1; i <= n; i++)
            {
                if (co[i] && cnt == k) break;
                if (co[i])
                {
                    cnt++;
                    cout << i << " ";
                }
            }
        }
        else
        {
            cnt = 0;
            cout << 1 << endl;
            for (int i = 1; i <= n; i++)
            {
                if (!co[i] && cnt == k) break;
                if (!co[i])
                {
                    cnt++;
                    cout << i << " ";
                }
            }
        }
    }
    else
    {
        st = Q[top], lst = st, top--;
        vis2[st] = 1;
        while (st != Q[top])
        {
            vis2[Q[top]] = 1;
            tail[Q[top]] = lst;
            lst = Q[top];
            top--;
        }
        tail[st] = lst;
        for (int i = 1; i <= m; i++)
        {
            if (vis2[u[i]] && vis2[v[i]] && tail[u[i]] != v[i] && tail[v[i]] != u[i])
            {
                for (int j = tail[u[i]]; j != v[i]; j = tail[j]) vis2[j] = 0;
                tail[u[i]] = v[i];
            }
        }
        for (int i = 1; i <= n; i++)
        {
            if (vis2[i])
            {
                st = i;
                cnt++;
            }
        }
        if (cnt <= k)
        {
            cout << 2 << endl << cnt << endl << st;
            for (int i = tail[st]; i != st; i = tail[i]) cout << " " << i;
        }
        else
        {
            cout << 1 << endl;
            k = (k+1)/2;
            for (int i = st; k; i = tail[tail[i]], k--) cout << i << " ";
        }
    }
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-12 22:45  David24  阅读(87)  评论(0编辑  收藏  举报