C1668 [Wannafly冬令营2018Day4]最小边覆盖

题目描述

给定一个无向连通简单图 GG(简单图的意思是无自环无重边),它的一个边覆盖是 GG 的边集 EE 的子集 SS,使得 GG 的点集 VV 中的任意一个点都出现在SS中的至少一条边中。这个边覆盖的大小定义为 SS 包含的边数。如果 SS 是所有 GG 的边覆盖中最小的,则称 SS 是图 GG 的最小边覆盖。

Gallai 证明了对任意无向连通简单图,它的最大匹配的大小加上最小边覆盖的大小一定等于它的点数。

于是,为了求出一个无向简单图的最小边覆盖,我们可以首先使用带花树算法求出它的最大匹配,然后仿照 Gallai 定理的证明构造出一个最小边覆盖。

这道题给定了无向连通简单图 GG 的点集,和图 GG 的边的一个子集 SS,但没有给出边集 EE。试判断 SS 有没有可能是图 GG 的最小边覆盖。

输入描述

第一行两个正整数 nn 和 mm 表示图 GG 的点数和 SS 的大小(1\le n\le 200000,1\le m\le 3000001≤n≤200000,1≤m≤300000)。接下来 mm 行每行两个正整数 a,ba,b 表示 SS 中的一条边 {a,b}a,b(点从11到nn编号,保证SS中没有自环和重边)。

输出描述

如果存在一个无向连通图 GG,使得GG的点集是 {1,\ldots,n}1,…,n,且 GG 的边集包含 SS,且 SS 是 GG 的一个最小边覆盖,则输出 “Yes”。否则输出 “No”。

样例输入 1

4 2
1 2
3 4
样例输出 1

Yes
样例输入 2

4 3
1 2
2 3
3 4
样例输出 2

No

思路:
没看懂题意,以为是判断s是否就是这张图的最小边覆盖。
但按照试验的结果,意思是判断s是否是最小边覆盖的子集。
那么任意一条边的两点度数不能同时大于1,否则就可以去掉这条边。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;
const int maxn = 3e5 + 7;

int vis[maxn],a[maxn],b[maxn];

int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= m;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
        vis[a[i]]++;
        vis[b[i]]++;
    }
    int flag = 1;
    for(int i = 1;i <= m;i++)
    {
        if(vis[a[i]] >= 2 && vis[b[i]] >= 2)
            flag = 0;
    }
    if(flag == 1)printf("Yes\n");
    else printf("No\n");
}

发布了594 篇原创文章 · 获赞 16 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/103530777