zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    C# 文件过滤器Filter
    C#实现打印功能
    Entity Framework 批量插入很慢
    C#关于日期月天数和一年有多少周及某年某周时间段的计算
    lc.exe 已退出 代码为 1
    oracle获取本月第一天和最后一天及Oracle trunc()函数的用法
    [ASP.NET AJAX]How to register javascript functions after UpdatePanel updated
    PPC调用webservice精要
    Oracle的思维(4)Oracle的万能分页并不万能2
    Microsoft Tech ED 2006
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11252979.html
Copyright © 2011-2022 走看看