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 购物 —— 贪心的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 那做HPV病毒检测要多少钱呢?
- 下一篇: jemeter监听器的使用