[POI2012]Tour de Bajtocja

本文介绍了解决POI2012 TourdeBajtocja问题的方法,该问题要求在无向图中删除最少数量的边,使编号小于等于k的点不在环上。通过分析,提出了一种正确的解决方案,并提供了时间复杂度为O(nα(n))的源代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[POI2012]Tour de Bajtocja

题目大意:

给定一个\(n(n\le10^6)\)个点\(m(m\le2\times10^6)\)条边的无向图,问最少删掉多少条边能使得编号小于等于\(k\)的点都不在环上,并输出任意一种删边方案。

思路:

首先若一条边两端都\(>k\),那么加上这条边对答案没有影响(就是说由它构成的环上如果有端点\(\le k\)的边,删掉后者不会更差)。

因此我们可以先将所有两端点都\(>k\)的边加上。对于有端点\(\le k\)的边,我们依次将它们加上,如果两端已经连通则不得不将这条边删去,可以证明答案是正确的。

时间复杂度\(\mathcal O(n\alpha(n))\)

源代码:

#include<cstdio>
#include<cctype>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
const int N=1e6+1,M=2e6;
struct Edge {
    int u,v;
};
Edge edge[M];
bool mark[M];
class DisjointSet {
    private:
        int anc[N];
        int find(const int &x) {
            return x==anc[x]?x:anc[x]=find(anc[x]);
        }
    public:
        void reset(const int &n) {
            for(register int i=1;i<=n;i++) anc[i]=i;
        }
        void merge(const int &x,const int &y) {
            anc[find(x)]=find(y);
        }
        bool same(const int &x,const int &y) {
            return find(x)==find(y);
        }
};
DisjointSet s;
int main() {
    const int n=getint(),m=getint(),k=getint();
    s.reset(n);
    for(register int i=0;i<m;i++) {
        const int &u=edge[i].u=getint();
        const int &v=edge[i].v=getint();
        if(u<=k||v<=k) continue;
        if(!s.same(u,v)) s.merge(u,v);
    }
    int ans=0;
    for(register int i=0;i<m;i++) {
        const int &u=edge[i].u;
        const int &v=edge[i].v;
        if(u>k&&v>k) continue;
        if(!s.same(u,v)) {
            s.merge(u,v);
        } else {
            ans++;
            mark[i]=true;
        }
    }
    printf("%d\n",ans);
    for(register int i=0;i<m;i++) {
        if(mark[i]) printf("%d %d\n",edge[i].u,edge[i].v);
    }
    return 0;
}

转载于:https://www.cnblogs.com/skylee03/p/9879340.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值