首页 > 其他 > 详细

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

时间:2019-07-26 21:55:43      阅读:57      评论:0      收藏:0      [点我收藏+]

题意

给定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;
}

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

原文:https://www.cnblogs.com/Chtholly/p/11252979.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!