zoukankan      html  css  js  c++  java
  • 洛谷 P1640 SCOI2010 连续攻击游戏 并查集

    题目描述

    lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示。当他使用某种装备时,他只能使用该装备的某一个属性。并且每种装备最多只能使用一次。游戏进行到最后,lxhgww遇到了终极boss,这个终极boss很奇怪,攻击他的装备所使用的属性值必须从1开始连续递增地攻击,才能对boss产生伤害。也就是说一开始的时候,lxhgww只能使用某个属性值为1的装备攻击boss,然后只能使用某个属性值为2的装备攻击boss,然后只能使用某个属性值为3的装备攻击boss……以此类推。现在lxhgww想知道他最多能连续攻击boss多少次?

    输入格式

    输入的第一行是一个整数N,表示lxhgww拥有N种装备接下来N行,是对这N种装备的描述,每行2个数字,表示第i种装备的2个属性值

    输出格式

    输出一行,包括1个数字,表示lxhgww最多能连续攻击的次数。

    输入输出样例

    输入样例

    3
    1 2
    3 2
    4 5
    

    输出样例

    2
    

    说明/提示

    Limitation

    对于30%的数据,保证N < =1000

    对于100%的数据,保证N < =1000000

    分析

    先来一个水过的代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    int ma[1000000];
    int main(){
    	int n;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		int aa,bb;
    		scanf("%d%d",&aa,&bb);
    		if(ma[aa]) ma[bb]++;
    		else if(ma[bb]) ma[aa]++;
    		else ma[min(aa,bb)]++;
    	}
    	for(int i=1;i<=1000001;i++){
    		if(!ma[i]){
    			printf("%d
    ",i-1);
    			return 0;
    		}
    	}
    	return 0;
    }
    

    思路大致是读入两个值后,如果有一个在之前已经选过了,那么选另一个,如果都没选过,就挑一个较小的选,要是都选过,就随便选

    但是这样显然是不太正确的,比如下面这组数据

    4

    3 2

    4 1

    3 1

    2 2

    正解应该是4,但上面的代码却输出3

    正解需要用并查集来解决

    每次读入装备的两个值后,如果两个值的祖先节点不相等,我们就将这两个值的祖先节点并在一起,用值较大的祖先节点作为父亲节点,同时将值较小的祖先节点标记为访问过;如果两个值的祖先节点相等,那么我们就将这个祖先节点标记为访问过

    那么这种做法和上面的做法区别在哪里呢

    其实就是在数据的处理上,比如上面的第二个装备4 1

    第一种方法会直接把4丢掉,而第二种方法则会把4记录下来,以为它还有可能对后面的答案做出贡献

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,m,fa[1000005];
    bool vis[1000005];
    int zhao(int xx){
        if(xx==fa[xx]) return xx;
        return fa[xx]=zhao(fa[xx]);
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=1000000;i++) fa[i]=i;
        for(int i=1;i<=n;i++){
            int aa,bb;
            scanf("%d%d",&aa,&bb);
            int xx=zhao(aa),yy=zhao(bb);
            if(xx==yy)vis[xx]=1;
            else {
                if(xx<yy)swap(xx,yy);
                fa[yy]=xx,vis[yy]=1;
            }
        }
        for(int i=1;i<=n+1;i++){
            if(!vis[i]){
                printf("%d
    ",i-1);
                break;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    网络编程(一)--网络编程介绍
    Python与设计模式之单例模式
    面向对象(六)--元类
    面向对象(五)--isinstance与issubclass方法、反射、内置方法(部分)、异常处理
    面向对象(四)--绑定方法与非绑定方法(classmethod、staticmethod装饰器)
    面向对象(三)--多态、封装、property装饰器
    面向对象(二)--继承与派生、组合
    Django之中间件
    Django之auth认证
    Django之form主键
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/12822739.html
Copyright © 2011-2022 走看看