题目描述

夏天的旅行是无限快乐,Alan想和自己最喜欢的小y开启旅程,可是小y却有着一些独自的看法!
Alan最近得到了一张London的地图,准备带着小y去旅行,其中详细标明了London内的n个景点,
其***有m条双向道路连接着这n个景点。但是由于小y的精力有限,她实在没有办法将n个景点全部都游览一
遍,于是只好算了一个她喜欢的数字k,她只想详细游览前k个景点,其他的等以后有机会再来。
受到了小y自己的困扰,小y特别害怕自己会在某个环上走来走去,她觉得这样的重复旅游去而导致可怕的事情发生,所以她希望
Alan能帮在地图上删去一些边,使得所有编号不大于k的所有景点都不在环上。

方法一:计算需要去掉的边

题目分析:题目要求的是使所有标号不大于k的所有景点都不在环上,那么我们可以先对起点和终点排序,把所有大号的都排在前面,然后我们利用并查集的思想,把这些点合并起来,如果两个点已经有公共祖先那么可以判断他们属于一个环上的点,如果这个环上的点有小于等于k的点,那么我们可以把这些边去掉。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 10;
int pre[maxn];

struct node
{
    int s, e;
    bool operator<(const node x) const
    {
        if (s != x.s)
            return s > x.s;
        return e > x.e;
    }
} w[maxn];
int find(int x)
{
    if (x != pre[x])
        pre[x] = find(pre[x]);
    return pre[x];
}
int main()
{
    int n, m, k;
    int ans = 0;
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; ++i)
        pre[i] = i;
    for (int i = 1; i <= m; ++i)
        scanf("%d%d", &w[i].s, &w[i].e);
    sort(w + 1, w + m + 1);
    for (int i = 1; i <= m; ++i)
    {
        if (find(w[i].s) == find(w[i].e))
        {
            if (min(w[i].s, w[i].e) <= k)
                ++ans;
        }
        else
            pre[find(w[i].s)] = find(w[i].e);
    }
    printf("%d\n", ans);
}

方法二:判断符合的边

我们首先判断如果两个点都大于k,那么这两个点形成的边是符合条件的,也就是不需要去掉的边,如果两个点不连通,那么就把它们连通起来,然后再遍历一次,如果两个点之间有小于等于k的点,并且他们不连通也就不符合提议条件,但是是不需要去掉的边,把它们加起来,然后使他们连通,最后用总的边数减掉不需要去掉的边就是符合题目要求的答案

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 10;
int n, m, k, pre[maxn];
int find(int x)
{
    return pre[x] == x ? x : pre[x] = find(pre[x]);
}
void join(int x, int y)
{
    pre[find(x)] = find(y);
}
int u[maxn], v[maxn];
int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i <= n; ++i)
        pre[i] = i;
    int ans = 0;
    for (int i = 1; i <= m; ++i)
    {
        scanf("%d%d", &u[i], &v[i]);
        if (u[i] > k && v[i] > k)
        {
            ans++;
            if (find(u[i]) != find(v[i]))
                join(u[i], v[i]);
        }
    }
    for (int i = 1; i <= m; ++i)
    {
        if (min(u[i], v[i]) <= k)
        {
            if (find(u[i]) != find(v[i]))
            {
                ++ans;
                join(u[i], v[i]);
            }
        }
    }
    printf("%d\n", m - ans);
    return 0;
}