游戏

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

题目链接:
==https://nanti.jisuanke.com/t/T2650==

现在也没有想太通为什么这题用并查集写..先挖个坑吧,说不定以后学的多了就渐渐明白了..
题解参考博客地址:http://hzwer.com/2950.html

把一个有a,b两种属性的武器看成点a,b之间的无向边
对于一个联通块,假如不含环(就是一棵树),那么必定可以满足其中任意的p-1个点。
对于一个联通块,假如含环,那么必定全部的p个点都能满足。
那么合并并查集的时候可以利用一个vis来维护这个性质
把权值看成点,把武器看成边, 如果每次加入的边是合并两个联通块 就把权值小的联通块并到权值大的联通块,然后给权值小的vis=true 如果不是就把该联通块的顶点的vis=true
这样就可以保证,如果一个大小为N联通块 =N-1条边构成,最大点的vis=false,其他为true;≥N条边构成,所有点的vis=true
然后最后只要一次扫描vis就可以得出答案了

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+50;

int n,f[N];
bool vis[N];

int found(int x){
    if(f[x]==x)return x;
    return f[x]=found(f[x]);
}

void unit(int x,int y){
    if(x>y)swap(x,y);
    if(vis[x]==1)vis[y]=1;
    vis[x]=1;
    f[x]=y;
}

int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=10000;i++){
        f[i]=i;
    }
    for(int i=1;i<=n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        x=found(x),y=found(y);
        if(x==y)vis[x]=1;
        else unit(x,y);
    }
    for(int i=1;i<=10001;i++){
        if(!vis[i]){
            printf("%d\n",i-1);
            return 0;
        }
    }
}

Supermarket

题目链接:==http://poj.org/problem?id=1456==

超市里有N个商品. 第i个商品必须在保质期(第di天)之前卖掉, 若卖掉可让超市获得pi的利润.
每天只能卖一个商品.
现在你要让超市获得最大的利润.

题解参考博客:https://blog.csdn.net/shuangde800/article/details/8022068

因为每卖一个产品要占用一个时间单位,所以,我们可以一个单位一个单位时间地依次决定,每个时间要卖哪个产品,并且保证每个单位时间卖出的产品都是利润最大的,这样便能保证最终结果是最大的。从最后一个截至时间开始往前枚举, 这样的话,只要把截止时间大于这个时间段的产品都放入优先队列,其中利润最大的便是这时间所要的。

先把所有产品按照利润从大到小排序,然后这个把这个放在截止日期那天卖出,并做好标记,如果截至日期那天已经有其他产品占用了,那么可以把这个产品卖出的时间往前推,直到找到可以卖的那一天并标记好。用并查集的关键之处是,我们知道按照上面那个方法,假设一个产品a占用了一个日期后,那么如果下次又有一个产品b和产品a的截止日期是相同的,但是那个日期以被占用了,所以就要往前移动1天,那么就可以用并查集进行标记,在a占用了那个日期后,把a的截止日期指向前一个日期,这样的话,可以直接查找到他要占用到哪一个时间。

代码:
贪心+优先队列(法一)按截止时间

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e4+50;

struct node{
    int p,d;
    bool operator <(const node &rhs)const{
        return d>rhs.d;
    }
}v[N];



int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        priority_queue<int> Q;
        int max_time=0;
        for(int i=0;i<n;i++){
            int p,d;
            scanf("%d%d",&p,&d);
            v[i]=(node){p,d};
            max_time=max(max_time,d);
        }
        sort(v,v+n);
        int cnt=0;
        long long sum=0;
        for(int i=max_time;i>=1;i--){
            for(;cnt<n;cnt++){
                if(v[cnt].d>=i){
                    Q.push(v[cnt].p);
                }
                else break;
            }
            if(!Q.empty()){
                sum+=Q.top();
                Q.pop();
            }
        }
        printf("%lld\n",sum);
    }
}

63ms
法二:按利润排序

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e4+50;

struct node{
    int p,d;
    bool operator <(const node &rhs)const{
        return p>rhs.p;
    }
}v[N];

bool vis[N]={0};

int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++){
            int p,d;
            scanf("%d%d",&p,&d);
            v[i]=(node){p,d};
        }
        sort(v,v+n);

        fill (vis,vis+N,0);
        long long sum=0;
        for(int i=0;i<n;i++){
            for(int j=v[i].d;j>=1;j--){
                if(!vis[j]){
                    vis[j]=1;
                    sum+=v[i].p;
                    break;
                }
            }
        }
        printf("%lld\n",sum);
    }
}

用并查集优化

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e4+50;

struct node{
    int p,d;
    bool operator <(const node &rhs)const{
        return p>rhs.p;
    }
}v[N];

int f[N];
bool vis[N];

void init(){
    for(int i=1;i<N;i++){
        f[i]=i;
    }
}

int found(int x){
    if(f[x]==x)return x;
    return f[x]=found(f[x]);
}


int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++){
            int p,d;
            scanf("%d%d",&p,&d);
            v[i]=(node){p,d};
        }
        init();
        sort(v,v+n);
        fill (vis,vis+N,0);
        long long sum=0;
        for(int i=0;i<n;i++){
            int m=found(v[i].d);
            if(m>0){
                sum+=v[i].p;
                f[m]=m-1;
            }
        }
        printf("%lld\n",sum);
    }
}