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

    幸甚至哉,歌以咏志。

  • 相关阅读:
    编程里的数字游戏
    SqlServer2005Express下的事件探查器
    来玩玩这个
    把一个bitmap在内存中的数据块 搬到另一个bitmap中
    一些常用的sql
    C#图像处理
    来玩玩画直线
    关于未来的思考
    年末个人小结
    [转载]编写超级可读代码的15个最佳实践
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12827457.html
Copyright © 2011-2022 走看看