【优先权队列求k大】Gym - 101234G Dreamoon and NightMarket

题解一看就会,就是自己想不到orz

题意:n种食物,价格分别为pi,每天都会选择不同的搭配来吃,并且会尽量先选便宜的组合,问第K天的伙食需要花费多少钱

一开始队友的思路是01背包来判断一个值是否可解,然后从前往后扫到第K个可解的值即为答案。但是存在一个问题:我们不知道最大价格能达到多少,设置的比较大的话本地跑都比较久,自然就T了,虽然这道题没A出来,但是和队友讨论的过程中对背包加深了理解,比如队友解决了我01背包一维必须倒序的疑惑。

这道题的正确思路是子集枚举

这个博客里面有一张图,赞~

对子集枚举还是掌握的不够好,这种方案完全就没想到,感觉有点像位向量法,每一种食物都有选和不选两种可能

参考博客2


#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
typedef pair<long long,int> pli;
priority_queue<pli,vector<pli>,greater<pli> >q;
const int N=2e5+10;
int p[N];
int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;++i)
        cin>>p[i];
    sort(p+1,p+1+n);
    int cnt=0;
    q.push(pli(p[1],1));            //pair->second代表的是当前方案中价格最贵的食物下标(考虑到的最后一个食物),first代表花费是多少
    while(true)
    {
        pli tmp=q.top();
        q.pop();
        cnt++;
        int idx=tmp.second;
        int pri=tmp.first;
        //cout<<pri<<' '<<idx;
        if(cnt==k)
        {
            cout<<pri<<endl;
            return 0;
        }
        if(idx<n)                //注意要保证数组不越界
        {

            if(pri+p[idx+1])
                q.push(pli(pri+p[idx+1],idx+1));
            if(pri+p[idx+1]-p[idx])
                q.push(pli(pri+p[idx+1]-p[idx],idx+1));
        }


    }
}


//#include<cstdio>
//#include<iostream>
//#include<cstring>
//#include<algorithm>
//#include<map>
//#include<vector>
//typedef long long ll;
//const int maxn = 2e5 + 10;
//using namespace std;
//map<ll, int> mp;
//vector<ll> vec;
//int p[maxn];
//int n, k;
//
//
//int main()
//{
//    cin >> n >> k;
//
//    int cnt = 0;
//    mp[0] = 1;
//    for(int i = 0; i < n; i++)
//        scanf("%d", &p[i]);
//    sort(p, p + n);
//    bool flag = false;
//    for(int i = 0; i < n; i++)
//    {
//        for(ll j = 1000000; j >= p[i]; j--)
//        {
//            cout<<i<<' '<<"?"<<endl;
//
//            if(mp[j - p[i]])
//            {
//                cout<<"?"<<endl;
//                mp[j]++;
//                cnt++;
//                cout << "cnt " << cnt << endl;
//                vec.push_back(j);
//
//            }
//        }
//        if(flag)    break;
//    }
//    cout<<vec[k-1]<<endl;
//    sort(vec.begin(), vec.end());
//    cout << vec[k - 1] << endl;
//    return 0;
//}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值