[SCOI2010]连续攻击游戏(二分图/并查集)

题意

给定n个物品,每个物品有两个属性(a,b)可选择,对每一个物品确定一个属性,使得1~k这些属性同时存在且k最大

思路

1. 二分图匹配

两个取能且仅能取一个,容易想到二分图,但是如果直接用a向b连边并不能解决问题,所以用a,b向编号i连边。WHY?这个亚子连边可以表示:①i只有一个属性,②一个属性a只需要和一个物品连边

然后for i 1~n 拿属性去一 一匹配物品,当不能匹配就结束循环

2. 并查集

将a直接向b连边,这样做会出现一些连通块,对于每一个连通块,如果它是一颗树,那么一定存在一种方法取点,使得只有一个点没有被取到;如果它不是一颗树,那么一定存在一个环,这种情况下所有点都能被取到

用并查集维护连通性,同时记录连通块是否有环、连通块大小

for i 1~n,如果i在环中则一定可以取,如果不在,但是连通块还有其它的点,优先选取i点,否则i+1之后的免谈\(......\)

Code:

#include<bits/stdc++.h>
#define N 1000005
using namespace std;
int n,t,size,maxx;
int fa[N],num[N];
bool cir[N];
template <class T>
void read(T &x)
{
    char c;int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
int find(int x) {return x==fa[x] ? x : fa[x]=find(fa[x]);}
int main()
{
    read(n);
    for(int i=1;i<=n+1;++i) fa[i]=i,num[i]=1;
    for(int i=1;i<=n;++i)
    {
        int x,y;
        read(x);read(y);
        int fx=find(x),fy=find(y);
        if(fx==fy) cir[fx]=1;
        else
        {
            cir[fx]=(cir[fx]|cir[fy]);
            cir[fy]=0;
            num[fx]+=num[fy];
            fa[fy]=fx;
        }
    }
    int i;
    for(i=1;i<=n+1;++i)
    {
        int fi=find(i);
        if(!cir[fi])//没有环才可能取不到
        {
            if(num[fi]==1) break;//没有边了,取不到
            --num[fi]; 
        }
    }
    cout<<i-1<<endl;
    return 0;
}

转载于:https://www.cnblogs.com/Chtholly/p/11252979.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值