(算法分析,无代码)洛谷P3063 [USACO12DEC]牛奶的路由Milk Routing

算法分析

乍一看以为是网络流,差点弃题,因为网络流还没看。。。但是显然这不是一道网络流,题目描述很明显,单源双向边最短路径问题,这道题关键在于边权的处理方面,所以先手算一下样例。开始的时候自己手算样例算半天一直不对,后来才看到下面还有一个说明提示(所以以后一定要多看说明提示里面的内容)
说明提示:
FJ wants to send 15 units of milk through his pipe network. Pipe #1 connects junction point 1 (the barn) to junction point 2, and has a latency of 10 and a capacity of 3. Pipes #2 and #3 are similarly defined.

The path 1->3 takes 14 + 15/1 = 29 units of time. The path 1->2->3 takes 20 + 15/2 = 27.5 units of time, and is therefore optimal.

约翰想要通过管网运送15个单位的牛奶。管道1连接节点1(谷仓)和节点2,延迟为10,容量为3。管道2和管道3也以相似的方式来定义。

路径1->3花费14+15/1=29个单位的时间。路径1->2->3花费20+15/2=27.5个单位的时间,用时最少。

算法分析:
起初的想法:可以把两个点之间的“距离”L+X/C分成两个部分来算第一部分是L,第二部分是X/C,可以先用单源最短路径的求法,在L+X/C中,针对从起点到终点的各个道路,算出该道路的“最窄部分”,然后苦思冥想,甚至结合了贪心的思路,最后都无法实现。因为每种路线的最窄部分都可能不一样,如果要打标记的话,不知道应该打在哪里。

更正后的思路:于是翻阅题解,然后幡然醒悟。原来可以从小到大枚举最多m种可能的容量,然后在每个容量的制约下再算最短路即可。(其实自己和最开始想的分成两部分有些相似之处,但是仔细一想是自己思考不足,自己的分成两部分的结果是第一部分可算,第二部分不可算。而改成枚举之后,就使得两部分都可以算了,因为在各个枚举情况下X/C的值是固定的)。

获得的启发:解题时遇到看起来很难算的,比如本题中的L+X/C,分成两个或者多个部分来算,再通过枚举等方式让各个部分都好算或者是在各个枚举情况下,其中一个部分好算,另外的部分固定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是P4087 [USACO17DEC]Milk Measurement的c++代码: ```c++ #include<bits/stdc++.h> using namespace std; int n,d,i,x,minn=1e9,maxn=-1e9,sum=7;//注意sum要初始化为7,因为一开始有三个人挤奶! map<int,int> mp; struct node{ int day,milk,id;//day表示某一天,milk表示这一天的产奶量,id表示这头牛的编号 }a[100010]; bool cmp(node x,node y){ return x.day<y.day; } int main(){ scanf("%d%d",&n,&d); for(i=1;i<=n;i++){ scanf("%d%d%d",&a[i].day,&a[i].id,&a[i].milk); minn=min(minn,a[i].id);//记录最小的牛的编号 maxn=max(maxn,a[i].id);//记录最大的牛的编号 } sort(a+1,a+n+1,cmp);//排序 for(i=1;i<=n;i++){ int p=a[i].id; mp[p]+=a[i].milk;//记录每头牛产奶总量 if(mp[p]-a[i].milk>=mp[minn]&&mp[p]>=mp[minn]){//如果这头牛的产奶总量减去这一天的产奶量后等于最小产奶量且这头牛的产奶总量大于等于最小产奶量 sum--; } if(mp[p]>=mp[maxn]&&mp[p]-a[i].milk<mp[maxn]){//如果这头牛的产奶总量大于等于最大产奶量且这头牛的产奶总量减去这一天的产奶量小于最大产奶量 sum++; } if(mp[p]-a[i].milk<mp[maxn]&&mp[p]>=mp[maxn]){//如果这头牛的产奶总量减去这一天的产奶量小于最大产奶量且这头牛的产奶总量大于等于最大产奶量 if(mp[maxn]-mp[p]+a[i].milk>0)sum++; } mp[p]-=a[i].milk;//减去这一天的产奶量 if(i==n||a[i].day!=a[i+1].day){//如果到了新的一天或者到了最后一天 if(mp[maxn]!=mp[a[i].id]&&mp[a[i].id]>=mp[maxn])sum++;//如果这头牛的产奶总量不等于最大产奶量且这头牛的产奶总量大于等于最大产奶量 if(mp[maxn]==mp[a[i].id]){//如果这头牛的产奶总量等于最大产奶量 if(a[i].id==maxn)sum+=0;//如果这头牛就是最大产奶量的牛,那么不需要增加计数器 else sum++;//否则需要增加计数器 } if(mp[minn]!=mp[a[i].id]&&mp[a[i].id]>=mp[minn])sum++;//如果这头牛的产奶总量不等于最小产奶量且这头牛的产奶总量大于等于最小产奶量 if(mp[minn]==mp[a[i].id]){ if(a[i].id==minn)sum+=0;//如果这头牛就是最小产奶量的牛,那么不需要增加计数器 else sum++;//否则需要增加计数器 } } } printf("%d\n",sum); return 0; } ``` 该题的解题思路是模拟,需要注意细节问题。我们可以首先将输入的数据按天数排序,然后模拟每一天挤奶的情况,并根据题目要求进行计数即可。具体细节请见代码注释。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值