zoukankan      html  css  js  c++  java
  • [SCOI2010] 连续攻击游戏

    题目

    原题链接

    解说

    抱歉有点事要忙只能引用了……
    这道题正解是用二分图,但是做完这道题的第二题才讲……所以我采用的我当时会的做法:并查集。

    我们每有一个武器(a, b)时我们可以把它当做一条边(a, b)。
    然后对于构图之后,一个大小为k联通块,我们发现有如下性质:
    ——如果这个联通块没有环(树):因为有k-1条边,那么总有方法使其中的k-1个节点被覆盖。容易知道这个联通块中一定不选最大的点。
    ——如果这个联通块有环:那么这k个节点一定都可以被覆盖
    这时我们可以用并查集去维护联通块有没有环,联通块的大小。
    然后我们扫一遍就行了……看看该联通块有没有环,如果没有环的话是不是看它是不是这个联通块的最大一个点。
    引自https://www.luogu.com.cn/blog/user1923/solution-p1640

    代码

    (注释我写的)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1000000+3;//注意开n的范围而不是开数的范围
    //因为攻击n次所以数最大只能用到n,后面比n大的都不用管
    int fa[maxn],size[maxn];
    bool cir[maxn];
    int find(int x){
    	if(fa[x]==x) return x;
    	return fa[x]=find(fa[x]);
    }
    int main(){
    	int n;
    	cin>>n;
    	for(int i=1;i<=n+1;i++) fa[i]=i;
    	for(int i=1;i<=n+1;i++) size[i]=1;//至今不太明白为啥这两行只初始化到n会WA,洛谷不给数据……
    	for(int i=1;i<=n+1;i++){
    		int a,b;
    		cin>>a>>b;
    		int faa=find(a),fab=find(b);
    		if(faa==fab) cir[faa]=1;//已经在一个集合里说明有环
    		else{//合并
    			cir[faa]=cir[faa]|cir[fab];
    			cir[fab]=0;
    			size[faa]+=size[fab];
    			size[fab]=0;
    			fa[fab]=faa;
    		}
    	}
    	int ans;
    	for(int i=1;i<=n+1;i++){
    		int fai=find(i);
    		if (!cir[fai]){
                if (size[fai]==1){
    				ans=i-1;
    				break;
    			}
                else size[fai]--;
            }
    	}
    	cout<<ans;
    	return 0;
    } 
    

    幸甚至哉,歌以咏志。

  • 相关阅读:
    上一篇、下一篇之实现思路
    sql优化
    简易的文件上传 tp5
    phpqrcode生成二维码
    php 发送邮件(2)qq邮箱开通
    php 发送邮件(1)代码逻辑
    SELECT list is not in GROUP BY clause and contains nonaggregated
    TP5 未定义变量:XXX
    CentOS 7下载
    FFT算法实现——基于GPU的基2快速傅里叶变换
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12827457.html
Copyright © 2011-2022 走看看