• BZOJ1854: [Scoi2010]游戏


    1854: [Scoi2010]游戏

    Time Limit: 5 Sec  Memory Limit: 162 MB
    Submit: 5931  Solved: 2397
    [
    Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    Sample Input

    3
    1 2
    3 2
    4 5

    Sample Output

    2

    HINT

    【数据范围】
    对于30%的数据,保证N < =1000
    对于100%的数据,保证N < =1000000



    题解

    首先我们把每个武器看做一条边,把权值看做点
    对于每条边最多只能选中其一个端点

    那么我们想象,如果有n个点形成了一棵树,那么我们能选中其中几个点?
    答案是n - 1个
    我们把树上每条边看做儿子向的链接,那么显然除了根节点都会有一条独属于自己的链接
    但如果有一个环就不一样了
    首先除了环外的部分看做树,树的根节点向环连边可以看做是属于根节点的边,而一个n元环有n条边刚好可以均匀分配,所以存在环的图一定可以都取到

    我们要找最长连续可取,我们只需标上哪些点可取,从1扫一遍就好了
    对于有环的图全都可取,对于树我们标树中最大的那个不可取

    怎么实现呢?
    用并查集。
    对于边(a,b),我们找到a,b所在联通块根节点fa,fb
    若fa != fb,将较小者的父亲记为较大者,标较小者为true,这样保证如果成树一定是最大的那个没有标上,若根本身就已经是true,说明已经成环,那么两者都标上true
    如果fa == fb,说明现在成环,都标true

    最后扫一遍vis就好了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define fo(i,x,y) for (int i = (x); i <= (y); i++)
    #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
    using namespace std;
    const int maxn = 10005,maxm = 1000005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1;char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
    	return out * flag;
    }
    int N,pre[maxn],n = 10000;
    bool vis[maxn];
    inline int find(int u) {return u == pre[u] ? u : pre[u] = find(pre[u]);}
    int main()
    {
    	int a,b,fa,fb;
    	N = read();
    	REP(i,n) pre[i] = i;
    	REP(i,N){
    		a = read(); b = read();
    		fa = find(a); fb = find(b);
    		if (fa > fb) swap(fa,fb);
    		if (fa != fb) {
    			pre[fa] = fb;
    			if (vis[fa]) vis[fb] = true;
    			vis[fa] = true;
    		}else vis[fb] = true;
    	}
    	REP(i,N + 1) if (!vis[i]) {printf("%d
    ",i - 1); break;}
    	return 0;
    }
    

  • 相关阅读:
    JAVA-初步认识-第三章-语句-switch
    JAVA-初步认识-第三章-if语句练习-星期和季节
    第三章-数据类型(3.3)
    JAVA-初步认识-第三章-局部代码块
    JAVA-初步认识-第三章-语句-if格式3
    JAVA-初步认识-第三章-语句-if格式1的演示
    JAVA-初步认识-第三章-语句-if格式2
    微信小程序图片使用示例
    推荐一款稳定快速免费的前端开源项目 CDN 加速服务
    基于mpvue的小程序项目搭建的步骤
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282831.html
Copyright © 2020-2023  润新知