• 1854: [Scoi2010]游戏



    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

    极简题解:

    一条边上的两个数字,优先让小数字打上标志。

    如果小数字已打上了,再让大数字来打。

    于是对于(a,b)来说,如果a<b,则较大的数字b,暂时不能打标记

    但再个(b,c),且b<c,则b就不是目前最大的数字了,C才是最大的数字,于是b也可以打上标记了。

    这正好符合并查集的传递性。

    Sol:

    这个题还是挺有意思的,思想用贪心和并查集。

    对于连接u,v的边。

    因为要保证攻击从1开始,于是我们每次用并查集去并的时候,强行让大的数字成为小的数字的父亲,并给小数字打上标志。

    这样一直连下去,于是整个集合的根结点是唯一没有被打上标记的点。

    于是当连接某个边,使得有环出现了,则这个时候,可以给集合的根结点打上标记了(因为整个集合只有它没打上标志了)

    此时如果再来连边,就发现边的一个端点u打了标记,但另一端点v还没打上标记,于是给v也打上标记好了。

    例如有以下物品时
    1 2
    2 3
    3 4
    2 5
    前三个构成如下图,只有4没有被选中

    对于第4个(2,5),2的父亲是4,5的父亲是5。
    于是用4连5,同时标志上4,5做为父亲点,图如下:

    如果此时再来个物品(1,5),则发现1与5在一个集合中了。(如果是来个(2,5)也是一样的)

    5是这个集合中唯一没有被标记上的,则此时就可以直接标记5了。

     如果此时再来个(5,6).则发现既然5已标记上了,于是6也就可以标记上了。

    想着:并查集本质上是一种树结构

    将每个装备看做边,装备属性看做点,每次合并两个点

    将过程想象成给点搭配边的过程

    这样得到的连通块有两类

    1、没有环,即边数=点数-1,那么对于树内的任意n-1的点,都可以搭配一条边,

    但题目要求从小到大攻击,所以先给小的搭配。也就是说,树内只有最大的点没有搭配边。

    如何实现这一过程?在合并时,让小的合并到大的上面,也就是始终让树内最大的点是祖先节点

    2、边数>=n,有环或有重边。

    #include<bits/stdc++.h>
    using namespace std;
    int ans,q,n,m,f[1008001];
    bool flag[1001011];
    int find(int x) {
    	if(f[x]==x) return x;
    	return f[x]=find(f[x]);
    }
    void coco(int x,int y) 
    {
    	if(flag[x]==true) 
    	    flag[y]=true;
    	else 
    	    flag[x]=true;
    	f[x]=y;
    }
    void unionset(int x,int y) 
    {
    	int xx=find(x);
    	int yy=find(y);
    	if(xx>yy) 
    swap(xx,yy); if(xx!=yy)
    //如果不在一个集合中,此时优先给编号小的(设为xx)打上标记,如果xx打过了,就给yy打标记 coco(xx,yy); else //如果在一个集合中,则此时集合中只有根结点没有打上标志了,于是给它打上 flag[xx]=true; } int main() { scanf("%d",&n); for(int i=1; i<=100001; i++) f[i]=i; for(int i=1,x,y; i<=n; i++) { scanf("%d%d",&x,&y); unionset(x,y); } for(int i=1; i<=100001; i++) if(flag[i]==false) { ans=i; break; } printf("%d",ans-1); return 0; }

    //wrong,这个程序对于一个环,再连一条边出来的情况,没有考虑到。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,fa[10001];
    bool v[10001];
    int find(int i)
    {
    return fa[i]==i ? i:fa[i]=find(fa[i]);
    }
    int main()
    {
    for(int i=1;i<=10000;i++) fa[i]=i;
    scanf("%d",&n);
    int a,b,r1,r2;
    for(int i=1;i<=n;i++)
    {
    scanf("%d%d",&a,&b);
    r1=find(a);r2=find(b);
    if(r1==r2) v[r1]=true;
    else
    {
    if(r1>r2) swap(r1,r2);
    fa[r1]=r2;
    v[r1]=true;
    }
    }
    int i;
    for(i=1;v[i];i++);
    printf("%d",i-1);
    }

  • 相关阅读:
    爬虫 比较好的视频推荐
    Scrapy爬取某装修网站部分装修效果图
    scrapy爬取阳光电影网全站资源
    爬虫练手实例
    Scrapy框架详解
    淘宝商品信息定向爬虫实例介绍
    Python基础第20天
    Python基础第19天
    Python基础第18天
    Python基础第17天
  • 原文地址:https://www.cnblogs.com/cutemush/p/14674013.html
Copyright © 2020-2023  润新知