日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

JZOJ 5461 购物 —— 贪心

發布時間:2023/11/27 生活经验 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JZOJ 5461 购物 —— 贪心 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目:https://jzoj.net/senior/#main/show/5461

?

?

貪心,原來想了個思路,優先選優惠價最小的 K 個,然后其他按原價排序遍歷;

如果當前物品沒選過,原價選上,如果選過,考慮把它換成原價,然后把優惠價最小的下一個選上;

但這樣做是75分,沒考慮 替換沒選過的物品 和 比較替換后是否更優;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const maxn=5e4+5;
int n,K,cnt;
ll m,ans;
bool vis[maxn];
struct N{int w,t,id;bool operator < (const N &y) const{return w>y.w;}
}p[maxn];
priority_queue<N>q;
bool cmp(N x,N y){return x.t<y.t;}
int main()
{freopen("shopping.in","r",stdin);freopen("shopping.out","w",stdout);scanf("%d%d%lld",&n,&K,&m);for(int i=1;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t);sort(p+1,p+n+1,cmp);for(int i=1;i<=n;i++)p[i].id=i,q.push(p[i]);for(int i=1;i<=K&&i<=n;i++){    if(ans+p[i].t>m)break;vis[i]=1; cnt=i; ans+=p[i].t;}if(cnt==n){printf("%d\n",n); return 0;}while(q.size()){int x=q.top().id,w=q.top().w,t=q.top().t; q.pop();if(!vis[x]){if(ans+w>m)continue;ans+=w; cnt++; }else{if(ans-p[x].t+p[x].w+p[K+1].t>m)continue;ans=ans-p[x].t+p[x].w+p[K+1].t; K++; cnt++;vis[x]=0; vis[K]=1;}}printf("%d\n",cnt);return 0;
}

正解是直接把選中物品的 原價 - 優惠價 放入小根堆,然后其他物品按原價排序,直接判斷、替換;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const maxn=5e4+5;
int n,K,cnt;
ll m,ans;
bool vis[maxn];
struct N{int w,t,id;}p[maxn];
priority_queue<int>q;
bool cmp(N x,N y){return x.t<y.t;}
bool cmp2(N x,N y){return x.w<y.w;}
int main()
{
//    freopen("shopping.in","r",stdin);
//    freopen("shopping.out","w",stdout);scanf("%d%d%lld",&n,&K,&m);for(int i=1;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t),p[i].id=i;sort(p+1,p+n+1,cmp);for(int i=1;i<=K&&i<=n;i++){    if(ans+p[i].t>m)break;cnt=i; ans+=p[i].t; q.push(p[i].t-p[i].w); vis[p[i].id]=1;}if(cnt==n){printf("%d\n",n); return 0;}sort(p+1,p+n+1,cmp2);for(int i=1,x;i<=n;i++){if(vis[p[i].id])continue;if(q.size()){x=-q.top();if(x+p[i].t>p[i].w&&ans+p[i].w<=m)ans+=p[i].w,cnt++;else if(x+p[i].t<=p[i].w&&ans+x+p[i].t<=m)ans+=x+p[i].t,cnt++,q.pop(),q.push(p[i].t-p[i].w);}else if(ans+p[i].w<=m)ans+=p[i].w,cnt++;} printf("%d\n",cnt);return 0;
}
TJ

但這樣總感覺不對,因為按原價排序并不能保證替換最優;

這里就是反例:

6 3 15

10 3

8 4

7 5

5 1

4 2

3 2

按這樣的做法,會先選后3個物品,然后按 1,2,3 把前三個物品排序;

然后把物品6換成原價購買,優惠價購買物品 3;

之后就不能買了,輸出4;

但實際上應該是優惠價購買物品 1,2,4,原價購買物品 5,6,答案是5;

?所以應該采用別的貪心策略,看到了一種很好的:https://blog.csdn.net/qq_40448823/article/details/81488195?(不過這篇博客貼錯題面了囧)

所有物品都按優惠價排序,同時開了一個原價購買的大根堆,存已經原價買下的東西的原價;

先買 K 個優惠價的,然后從優惠價排序的順序繼續往后看,每次去掉優惠買中 原價 - 優惠價 最小的一個,優惠價買下一個;

然后回頭看看能否原價買上去掉的這個東西,能就原價買上,不能就去原價物品堆里看看,如果能替換一下使花錢更少,那么就替換一下;

而如果優惠價購買下一個不如原價購買下一個優,那么原價購買下一個,同樣進行替換的判斷;

然后就能過掉上面的數據了,主要是因為優惠價部分排序滿足,原價部分用大根堆替換來滿足;

不過數據太水,也不知道這個做法是否完美無瑕,看樣子應該沒問題,先放到這里吧。

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const maxn=50005;
int n,K,ans;
ll sum,m;
struct N{int w,t,c;bool operator < (const N &y) const{return c>y.c;}
}p[maxn];
priority_queue<N>Q;
priority_queue<int>q;
bool cmp(N x,N y){return x.t<y.t;}
int main()
{freopen("shopping.in","r",stdin);freopen("shopping.out","w",stdout);scanf("%d%d%lld",&n,&K,&m);for(int i=1;i<=n;i++)scanf("%d%d",&p[i].w,&p[i].t),p[i].c=p[i].w-p[i].t;sort(p+1,p+n+1,cmp);for(int i=1;i<=n;i++){if(Q.size()<K&&sum+p[i].t<=m){sum+=p[i].t; ans++; Q.push(p[i]);}//Q是按差價排序的堆 else if(Q.size()==K)//其他物品是按優惠價排序的 
        {N x=Q.top();if(x.c+p[i].t<=p[i].w)//優惠價購買較優 
            {Q.pop(); Q.push(p[i]); sum=sum-x.t+p[i].t;//先優惠價買上 if(sum+x.w<=m){sum+=x.w; ans++; q.push(x.w);}//可以原價買原來那個 //q是原價購買了的堆 else if(q.size()&&q.top()>x.w){sum=sum-q.top()+x.w; q.pop(); q.push(x.w);}//不能買了,換掉之前原價購買的一個物品,可以更優
            }else if(sum+p[i].w<=m){sum+=p[i].w; ans++; q.push(p[i].w);}//原價購買 else if(q.size()&&q.top()>p[i].w){sum=sum-q.top()+x.w; q.pop(); q.push(x.w);}//不能買了,替換更優 
        }}printf("%d\n",ans);return 0;
}

?

轉載于:https://www.cnblogs.com/Zinn/p/9439885.html

總結

以上是生活随笔為你收集整理的JZOJ 5461 购物 —— 贪心的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。