POJ - 1456 利用并查集进行优化 + 贪心

题目

在这里插入图片描述

题解思路

必然是贪心,但是贪心策略想不出,还是太弱了,这题朴素贪心居然也能过,数据太弱了。
大佬的博客 看到的贪心策略。
将商品的价格从大到小排序,每次让商品从过期时间往前选择,这样对其他商品造成的影响就是最小的。
用朴素的方法的话,时间复杂度为 N平方 数据为1e4 应该要到极限才对。
我们可以用并查集优化, 将空闲的时间连接起来,因为进行了路径压缩,所以能节省复杂度。
将时间数组初始化为 -1 。
每次使用时,对时间进行find,返回离节点最近的空闲时间,使用后将时间指向时间-1的节点。

	int find2( int x )
	{
	    if ( -1 != pe[x] )
	    {
	        pe[x] = find2(pe[x]);
	        return pe[x];  //用于压缩路径
	    }
	    return x;    //这里返回节点
}

这个find函数有些难理解,建议手模下。

AC代码

并查集优化

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct sp
{
    int w,t;
    bool operator < (const sp &other) const
    {
        return w > other.w;
    }
}a[10010];
int  pe[10010];
int find2( int x )
{
    if ( -1 != pe[x] )
    {
        pe[x] = find2(pe[x]);
        return pe[x];
    }
    return x;
}
int main ()
{
    int n;
    while(~scanf("%d",&n))
    {
        int ans = 0;
        memset(pe,-1,sizeof(pe));
        for (int i = 1 ; i <= n ; i++ )
        {
            int j,k;
            scanf("%d%d",&j,&k);
            a[i].w = j;
            a[i].t = k;
        }
        sort(a+1,a+1+n);
        for (int i = 1 ;i <= n ; i++ )
        {
            int time = find2(a[i].t);
            if ( time > 0 )
            {
                ans += a[i].w;
                pe[time] = time - 1;
            }
        }
        cout<<ans<<"\n";

    }
    return 0;
}

朴素贪心

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct sp
{
    int w,t;
    bool operator < (const sp &other) const
    {
        return w > other.w;
    }
}a[10010];
bool slo[10010];
int main ()
{
    int n;
    while(~scanf("%d",&n))
    {
        int ans = 0;
        memset(slo,0,sizeof(slo));
        for (int i = 1 ; i <= n ; i++ )
        {
            int j,k;
            scanf("%d%d",&j,&k);
            a[i].w = j;
            a[i].t = k;
        }
        sort(a+1,a+1+n);
        for (int i = 1 ;i <= n ; i++ )
        {
            for (int k = a[i].t ; k > 0 ; k-- )
            {
                if (slo[k] == 0 )
                {
                    slo[k] = 1;
                    ans += a[i].w;
                    break;
                }
            }
        }
        cout<<ans<<"\n";

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值