运输问题--替换型贪心
来源:互联网 发布:mac怎么新建txt文件 编辑:程序博客网 时间:2024/05/18 09:22
多的不说,看题:
一、游客运输
风景迷人的阆中市,拥有n个美丽景点,编号为1..n。由于慕名而来的游客越来越多,市政府特意安排了一辆容量为C的观光公交车,为游客提供便捷的交通服务。观光公交每天早上从1号景点出发,一次前往2,3,…n号景点,每天只开一趟。
设某天有m位游客,每位乘车1次,第i位游客希望从景点Li到达景点Ri(1<=Li<=Ri<=n)。
现在给你观光公交的容量C,同事提供给你每位乘客的信息,请你计算这一天中最多能满足都少个人的愿望。
【输入格式】
第一行包含两个整数n,m,C,分别表示景点数目、游客数目和观光公交的容量。
第2行到第m+1行,每行包含两个整数:Li,Ri,其中第i+1行表示奶牛i想从景点Li到达Ri。
【输出格式】
一个整数,表示能满足的游客数量。
【输入样例】
10 8 3
8 10
1 9
2 10
6 8
5 8
6 7
3 5
4 6
【输出样例】
6
【数据范围】
n,m,C<=200000
观察到乘客的区间是一条线段,左右端点有一定的先后顺序。
可以考虑按某一端点排序之后贪心计算;
对于一个乘客,如果有空位,就直接坐
如果没有空位,可以替换一个要做更久的人
想象一列火车从左向右开,乘客依次上车;到了没有位置的时候,这时为了更好地满足后面乘客的需求,可以找一个下车时间在该乘客之后的乘客下车,然后让乘客i上车;
可以用优先队列或者是set维护。
这里用的set:
#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<iostream>#include<set>using namespace std;int n,m,c,ans=0;struct ge{ int l,r; friend bool operator<(ge x,ge y) { return x.l<y.l; }}a[200005];multiset<int>s;multiset<int>::iterator it;int main(){ scanf("%d%d%d",&n,&m,&c); for(int i=1;i<=m;i++) scanf("%d%d",&a[i].l,&a[i].r); sort(a+1,a+1+m); for(int i=1;i<=m;i++) { if(a[i].l==a[i].r) { ans++; continue; } it=s.begin(); while(!s.empty() && *it<=a[i].l)//删除已经下车的人 { s.erase(it); it=s.begin(); } if(s.size()<c)//有空位 { ans++; s.insert(a[i].r); } else //找人替换 { it=--s.end(); if(*it>a[i].r) { s.erase(it); s.insert(a[i].r); } } } printf("%d",ans); return 0;}
二、奶牛航班
【问题描述】
为了表示不能输给人类,农场的奶牛们决定成立一家航空公司。他们计划每天清晨,从密歇根湖湖岸的最北段飞向最南端,晚上从最南端飞往最北端。旅途中,航空公司可以安排飞机停在某些机场,他们需要你帮助来决定每天携带那些旅客。
沿着湖岸,有N个由北到南编号为1到N的农场。每个农场都有一个机场,这填,有k群牛想要乘坐飞机旅行。每一群牛想要从一个农场飞往另一个农场,航班可以在某些农场停下来带上部分或全体牛。奶牛们登记后会一直停留直至到达目的地。
提供给你飞机的容量为C,同时提供给你想要旅行的奶牛信息,请你计算出这一天的航班最多能满足几只奶牛的愿望。
【输入格式】
第1行有3个整数:K,N,C。接下来的K行,每行包含3个整数:S,E,M,表示有M只奶牛想从农场S乘飞机到农场E。
【输出格式】
可以完成旅行的奶牛人数的最大值。
【输入样例】
4 8 3
1 3 2
2 8 3
4 7 1
8 3 2
【输出样例】
6
【样例解释】
有3群奶牛旅行,8个农场,飞机上有3个作为。造成,飞机把2只牛从1带到3,1只从2带到8,1只从4带到7.晚上,航班把2只牛从8带到3。
【数据范围】
1<=N<=10000
1<=K<=50000
1<=C<=100
当然一来一回分两次计算就行了
和上题有不同的地方在于相同路段的乘客有多个:
思路大致相同,但是这里计算容量就不能再用s.size()了,而要新开一个数组c[x]表示在x下车的乘客数量,并用now表示当前车的容量;对于每个乘客来说同样有两种情况,有空位或把人踢下车;
要注意的就是情况有点多,所以写得有点复杂。。。orz
用优先队列实现的;
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<queue>using namespace std;typedef long long LL;const int maxn=50005;const int maxm=40005;int K,n,C,c1,c2,c[maxn],now,last,ans,l,r,s;struct data{ int l,r,s; friend bool operator <(data a,data b){ return a.r<b.r; }}t,tt,a[maxn],b[maxn];bool cmp(data a,data b){ return a.l<b.l;}void work1(){ priority_queue<data>q; sort(a+1,a+1+c1,cmp); now=C,last=0; for(int i=1;i<=c1;i++){ while(!q.empty() && q.top().r<=a[i].l) q.pop(); while(last<=a[i].l) now+=c[last++]; if(now){//有位置 if(now>=a[i].s){ q.push(a[i]); now-=a[i].s; ans+=a[i].s; c[a[i].r]+=a[i].s; a[i].s=0; } else{ q.push((data){a[i].l,a[i].r,now}); ans+=now; a[i].s-=now; c[a[i].r]+=now; now=0; } } if(a[i].s){//把终点在i后面的踢下去 s=0; while(!q.empty()){ if(s<a[i].s && a[i].r<q.top().r){ if(s+q.top().s<=a[i].s){ s+=q.top().s; c[q.top().r]-=q.top().s; q.pop(); } else{ t=q.top(); c[q.top().r]-=a[i].s-s; t.s-=a[i].s-s; s=a[i].s; q.pop();q.push(t); } } else break; } if(s){ q.push((data){a[i].l,a[i].r,s}); c[a[i].r]+=s; } } }}void work2(){ memset(c,0,sizeof(c)); priority_queue<data>q; sort(b+1,b+1+c2,cmp); now=C,last=0; for(int i=1;i<=c2;i++){ while(last<=b[i].l) now+=c[last++]; if(now){//有位置 if(now>=b[i].s){ q.push(b[i]); now-=b[i].s; ans+=b[i].s; c[b[i].r]+=b[i].s; b[i].s=0; } else{ q.push((data){b[i].l,b[i].r,now}); ans+=now; b[i].s-=now; c[b[i].r]+=now; now=0; } } if(b[i].s){//把终点在i后面的踢下去 s=0; while(!q.empty() && s<b[i].s && b[i].r<q.top().r){ if(s<b[i].s && b[i].r<q.top().r){ if(s+q.top().s<=b[i].s){ s+=q.top().s; c[q.top().r]-=q.top().s; q.pop(); } else{ t=q.top(); c[q.top().r]-=b[i].s-s; t.s-=b[i].s-s; s=b[i].s; q.pop();q.push(t); } } else break; } if(s){ q.push((data){b[i].l,b[i].r,s}); c[b[i].r]+=s; } } }}char ch;void _scanf(int &x){ x=0; ch=getchar(); while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();}int main(){// freopen("in.txt","r",stdin); scanf("%d%d%d",&K,&n,&C); ans=0,c1=c2=0; for(int i=1;i<=K;i++){ _scanf(l);_scanf(r);_scanf(s); if(l==r){ ans++;continue; } if(l<r) a[++c1]=(data){l,r,s}; else b[++c2]=(data){r,l,s}; } work1(); work2(); printf("%d\n",ans); return 0;}
三、火车运输
【问题描述】
ByteLand火车站(编号0)每天都要发往全国各地N列客运火车,编号1 N。第i列火车的目的地是编号Si的火车站。
对任意车站X,都与X+1车站有铁轨直接相连,因此火车站可以看成数轴上的整数点,第i列火车可以停靠区间[0, Si]中的各个站点。每列火车装载乘客的最大容量为Ci。有M个人需要乘坐火车。已知每个人的乘车区间为[Li, Ri],即是说,在Li上车,在Ri下车。
由于火车的容量限制,请你求出最多有多少人的乘车需求可以得到满足。
【输入格式】
第1行:2个整数N和M。
接下来N行,每行2个整数Si和Ci,表示第i辆车的目的站和容量。
接下来M行,每行2个整数Li和Ri,表示第i个乘客的乘车区间。
【输出格式】
第1行:1个整数,表示最多有多少乘客的乘车需求可以满足
【输入样例】
1 3
10 2
1 5
3 7
4 9
【输出样例】
2
【数据范围】
对于20%的数据,
N= 1, 1 ≤ M ≤ 10^5
1 ≤Si,Ci ≤ 10^9
1 ≤ Li ≤ Ri ≤ 10^9。
对于另外20%的数据,
1 ≤ N,M ≤ 2000
1 ≤Si,Ci ≤ 10^9
1 ≤ Li ≤ Ri ≤ 10^9。
对于100%的数据,
1 ≤ N,M ≤ 10^5
1 ≤Si,Ci ≤ 10^9
1 ≤ Li ≤ Ri ≤ 10^9。
和二不同的是火车也有多个;
意思就是火车在不同的时间的容量是不同的?!!
但是火车有公共的起点1。我们当然不能让火车开着开着容量就减少了,这样怎么贪心计算。。。所以我们把终点看成起点,火车从终点开向起点,乘客也从终点走到起点,所以我们按照右端点从大到小排序,并从右向左枚举乘客;
对于一个(右端点靠右)乘客,我们要尽可能用右端点靠右的公交装(因为右端点稀有)
所以我们把乘客按照右端点从大到小开始枚举 (一开始把第一个公交也无法装的乘客直接删掉)
枚举每个乘客能否装在公交里;首先应将新加进队伍中的公交(bus[j].r>=pas[i].r)的容量加入now中,且由于容量是now的公交可以看成是now个容量为1的公交,所以我们可以分开考虑c个公交的情况和当前车上的人数,从而简化了模型
我们就可以更新出车的现在可用容量并把装有人的车(的目的地)甩进set中。
转换模型之后就是游客运输了; 乘客能装有两个选择: 1.有空车 2.车上的人比当前乘客下得还早(s.begin()<pas[i].l) 当然要维护当前车的总可用容量(下车) cnt[i]记录在点i的下车人数
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<set>using namespace std;const int maxn=1000005;int n,m,cnt[maxn],last,ans,now;struct passenger{ int l,r; friend bool operator <(passenger a,passenger b){ if(a.r==b.r) return a.l>b.l; return a.r>b.r; }}pas[maxn];struct route{ int s,c; friend bool operator <(route a,route b){ return a.s>b.s; }}bus[maxn];multiset<int>s;multiset<int>::iterator it;void work(){ sort(bus+1,bus+1+n); sort(pas+1,pas+1+m); int i=1,j=1; last=bus[1].s; while(i<=m && pas[i].r>bus[1].s) i++; for(;i<=m;i++){ while(j<=n && bus[j].s>=pas[i].r){ now+=bus[j].c,j++; } while(last>pas[i].r && last>0){ now+=cnt[--last]; } if(now){ now--,cnt[pas[i].l]++,ans++; s.insert(pas[i].l); } else{ it=s.begin(); if(it==s.end()) continue; int t=*it; if(t<pas[i].l){ cnt[t]--,cnt[pas[i].l]++; s.erase(it); s.insert(pas[i].l); } } } printf("%d\n",ans);}char ch;void _scanf(int &x){ x=0; ch=getchar(); while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();}int main(){// freopen("in.txt","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ _scanf(bus[i].s);_scanf(bus[i].c); } for(int i=1;i<=m;i++){ _scanf(pas[i].l);_scanf(pas[i].r); } work(); return 0;}
反正就是更新状态+替换啦~
- 运输问题--替换型贪心
- 贪心 运输
- 运输问题
- 运输问题
- 运输问题
- 贪心--2016cqround4火车运输
- 【题】【贪心】NKOJ3827 火车运输
- nefu492运输问题
- mmc运输问题
- mmc生产运输问题
- wikioi1914 运输问题
- wiki 1914 运输问题
- [codevs 1914] 运输问题
- 运输问题2
- [BZOJ3573]HNOI2017米特运输|贪心
- 骆驼运输香蕉问题解析
- mmc生产运输投资问题
- 用lingo解决运输问题
- EventBus使用
- spring 底层实现IOC DI简单依赖反射
- mysql安装与基本操作
- 隐藏QT窗口在任务栏中的图标
- Guava ListenableFuture 实现多线程 先执行完线程任务 ,再来执行主线程
- 运输问题--替换型贪心
- mybatis查询sql:where语句“查询时间字段书写问题”引发的索引失效
- Logo
- Web前端高效开发总结二:HTML最佳实践
- 性能之战:HTTPS PK HTT
- 86. Partition List
- 121. Best Time to Buy and Sell Stock
- 【主席树】51Nod 1175 区间中第K大的数
- oracle学习(使用了PL/SQL)——2