145. 超市 AcWing
考察:并查集+贪心或堆排序+贪心
因为最近在做并查集专题所以直接考虑用并查集写,但是看题目完全没有想到用并查集的方式,以前写的并查集题目关系的传递性都很明显,但是这道题本蒟蒻完全没看出来
思路:
用并查集维护天数,贪心策略是能多晚卖出就多晚卖出,起初每个天数都在它自己的集合里,当我们决定要卖出此商品时(设过期天数为d),那么第d个位置就被占用了,我们需要让d这个位置指向在它前面第一个空闲的位置.因为是和它前面的链接,所以直接链接d与d-1即可.当所指的位置到0,那么说明这个商品不能被卖出,利用路径压缩可以把时间复杂度压到O(1)
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 typedef pair<int,int> pii; 5 const int N = 10010; 6 int p[N]; 7 pii goods[N]; 8 struct cmp{//按价值排序 9 bool operator()(pii x,pii y){ 10 return x.first>y.first; 11 } 12 }; 13 int find(int x) 14 { 15 if(x!=p[x]) p[x] = find(p[x]); 16 return p[x]; 17 } 18 int main() 19 { 20 int t; 21 while(scanf("%d",&t)!=EOF){ 22 fill(p,p+N,0); int ans = 0; 23 for(int i=1;i<=t;i++) scanf("%d%d",&goods[i].first,&goods[i].second); 24 for(int i=1;i<=N-10;i++) p[i] = i; 25 sort(goods+1,goods+t+1,cmp()); 26 for(int i=1;i<=t;i++){ 27 int px = find(goods[i].second); 28 if(px){ 29 ans+=goods[i].first; 30 p[px] = find(px-1); 31 } 32 } 33 printf("%d\n",ans); 34 } 35 return 0; 36 }
每天在orz算法竞赛进阶指南....
2021.2.20 二刷与本题差不多的题 Doing Homework again HDU - 1789
还是不会,md醉了.
主要是贪心策略的选择.这里不采用并查集方法.将作业按日期排序,用一个堆维护.堆大小要么比当前作业天数小,要么与天数相同.如果相同去掉价值最小的即可.
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 using namespace std; 7 const int N = 1010; 8 typedef pair<int,int> PII; 9 PII work[N]; 10 int main() 11 { 12 int T; 13 scanf("%d",&T); 14 while(T--) 15 { 16 int n,ans = 0; 17 scanf("%d",&n); 18 priority_queue<int,vector<int>,greater<int> > q; 19 for(int i=1;i<=n;i++) scanf("%d",&work[i].first); 20 for(int i=1;i<=n;i++) scanf("%d",&work[i].second); 21 sort(work+1,work+n+1); 22 for(int i=1;i<=n;i++) 23 { 24 if(work[i].first>q.size()) q.push(work[i].second); 25 else{ 26 if(q.top()<work[i].second) 27 { 28 ans+=q.top(); 29 q.pop(); q.push(work[i].second); 30 }else ans+=work[i].second; 31 } 32 } 33 printf("%d\n",ans); 34 } 35 return 0; 36 }
2021.3.7 三刷 并查集的方法还是没有学会,直接连接该天的前一天,就算前一天被占用了,会找到前面没有被占的天