HOJ 1225 Suptermarket(并查集)

题意:

先给出商品个数n,然后对于每一个商品ai{pa,da},pa代表这个商品的利润,da代表这个商品必须在第d天之前售出. 每天只能卖出一个商品

问如何安排卖的顺序,使得利润最大.输出最大利润


分析:

根据贪心的策略,按利润排序,利润最大的放在最前面.

按ddl分集合

ddl=1的集合,只能在0~1的时间卖.

ddl!=1的集合,除了在ddl那天卖,还能在ddl之前的某一天卖,所以将ddl的商品,做成ddl-1的商品的子树.


#include <iostream>  //按deadline进行分集合
#include <cstdio>
#include <memory.h>
#include <algorithm>
using namespace std;

int father[10010];    //father[i]表示元素i的父亲节点
int rank[10010];
struct Goods
{
    int val;
    int ddl;

} aa[10010];

int Find_set(int x)
{

    if(x!=father[x])
    {
        rank[x]++;//每递归一层,说明树高+1,秩+1
        father[x]=Find_set(father[x]);  //进入递归时,是寻找根结点。找到根结点后(根结点必定是father[x]==x的),递归返回,顺便压缩路径,把路径上的所有结点的father[]都指向了root
    }
    return father[x];
}

void unitebyrank(int x,int y)  //按秩合并x,y两元素所在的集合。 关于这个秩,可以是树的深度,节点个数等启发函数.根据需要进行选择.
{
    x=Find_set(x);
    y=Find_set(y);//找到x,y所在集合的根结点;
    if(x==y)return; //如果根结点相同,说明x,y本来就在同一个集合内。不用再合并。
    else
    {
        if(rank[x]>rank[y])
        {
            father[y]=x;    //按秩合并。如果x所在集合的秩比y的大,那么将y所在集合作为子树合并到x上。
        }
        else
        {
            if(rank[x]==rank[y])rank[y]++;
            father[x]=y;
        }
    }
}

void unite(int x,int y)
{
    int xx=Find_set(x);
    int yy=Find_set(y);
    father[xx]=yy;
}

bool cmp(Goods a,Goods b)
{
    return a.val>b.val;
}
bool visited[10010];    //记录该集合是否被访问过。本题中按goods.ddl划分集合。ddl相同的商品
int main()
{
    int n;
    while(scanf("%d",&n))
    {
        memset(visited,false,sizeof(visited));
        for(int i=0; i<10010; i++)
        {
            father[i]=i;    //对father[]进行初始化。刚开始,认为每一个商品i都是一个集合(集合中只有它一个元素),因此father[i]=i;
            rank[i]=0;     //对每一集合的秩进行初始化
        }
        for(int i=0; i<n; i++)
        {
            scanf("%d %d",&aa[i].val,&aa[i].ddl);
        }
        sort(aa,aa+n,cmp);//对goods进行降序排列,因为根据贪心策略,要先排val最大的商品。
        int sum=0;
        for(int i=0;i<n;i++)
        {
            int temp;
            temp=Find_set(aa[i].ddl);  //查找该商品的ddl所在集合的根结点
            if(visited[temp]==false)  //如果该ddl的集合尚未被访问过
            {
                visited[temp]=true;
                sum+=aa[i].val;
            }
            if(temp!=1)   //ddl=1的集合,只能在0~1时间卖
            unite(temp,temp-1);  //ddl!=1的集合,除了在ddl那天卖,还能在ddl之前的某一天卖。所以将ddl那天,做成ddl-1那天的子树。
                                //注意这时就不要按秩合并了。

        }
        printf("%d\n",sum);
    }
    return 0;
}

转载于:https://www.cnblogs.com/MicZ/archive/2012/10/21/2785361.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值