洛谷P5837 [USACO19DEC]Milk Pumping Gnode
洛谷P3063 [USACO12DEC]Milk Routing Sc++
给定\(N\)个点和\(M\)条边,对于每条边,给定链接的两个端点以及这条边的花费和“流量”spa
设这条路径上全部边的花费总和为\(L\).net
设这条路径上全部边中“流量”值最小的为\(C\)code
要求找出一条\(1\)到\(N\)的路径知足:\(L\)尽量小的同时\(C\)尽量大(注意是一条路径上的L和C)blog
若是是单独求\(L\)或者\(C\)中的一个,那么咱们很容易便能解决get
可是若是要求同时维护\(L\)和\(C\)两个值,并且这两个值仍是矛盾的,那咱们怎么作呢?it
(这里的矛盾指:\(L\)要尽可能小,而同一条道路的\(C\)又要尽可能大)io
首先咱们先来考虑用一个最短路同时维护这两个值,但通过一番思索,咱们会发现没法作到class
为何?由于这两个值矛盾啊!相矛盾的两个值怎么能在同一个最短路中解决呢?
否认了同时维护的想法,咱们只能考虑分开维护,分开维护?多个最短路?
确定也不行,为何?维护出来的\(L\)、\(C\)分别对应的最短路径不必定是同一条啊!最短路径都不是同一条那\(L\)、\(C\)怎么会相对应呢?
同时维护和分开维护都不行,那怎么作?
枚举
什么意思?
咱们要维护对应的两个值,那咱们能够枚举其中一个值,而后再在枚举的这个值的基础上去寻找对应的另外一个值呀!
怎么实现呢?
假设咱们枚举\(Ci\),而后跑最短路去求解对应的\(Li\),在跑最短路时判断当前点\(v\)的\(Cv\)值是否小于\(Ci\),若是小于那么就无论这个点(由于咱们枚举的\(Ci\)已是假定的最小流量值,那么全部小于\(Ci\)确定没有用)
为何\(Ci\)是假定的最小流量值?不是求最大的\(C\)吗?
咱们不断枚举\(Ci\),找到全部对应的\(Li\),而后用一个\(ans\)来记录最终的答案,最终找到的必定是最大的\(C\)和最小的\(L\)
#include <bits/stdc++.h> using namespace std; int n,m,a,b,c,f,tot,ans; int dis[100010],vis[100010],head[100010]; priority_queue<pair<int,int> > shan; struct node { int to,net,liu,val; } e[100010]; inline void add(int u,int v,int w,int l) { e[++tot].to=v; e[tot].net=head[u]; e[tot].liu=l; e[tot].val=w; head[u]=tot; } inline void dijkstra(int l) { memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[1]=0; shan.push(make_pair(0,1)); while(!shan.empty()) { int x=shan.top().second; shan.pop(); if(vis[x]==1) continue; vis[x]=1; for(register int i=head[x];i;i=e[i].net) { int v=e[i].to; if(e[i].liu<l) continue; if(dis[v]>dis[x]+e[i].val) { dis[v]=dis[x]+e[i].val; shan.push(make_pair(-dis[v],v)); } } } } int main() { scanf("%d%d",&n,&m); for(register int i=1;i<=m;i++) { scanf("%d%d%d%d",&a,&b,&c,&f); add(a,b,c,f); add(b,a,c,f); } for(register int li=1;li<=1000;li++) { dijkstra(li); if(dis[n]!=0x3f) ans=max(ans,li*1000000/dis[n]); } printf("%d",ans); return 0; }
#include <bits/stdc++.h> using namespace std; int n,m,x,u,v,w,c,tot,ans=20050206; int dis[510005],vis[510005],head[510005],flag[510005]; priority_queue<pair<int,int> > shan; struct node { int to,net,val,liu; } e[510005]; inline void add(int u,int v,int w,int l) { e[++tot].to=v; e[tot].val=w; e[tot].liu=l; e[tot].net=head[u]; head[u]=tot; } inline void dijkstra(int li) { for(register int i=1;i<=n;i++) { vis[i]=0; dis[i]=20050206; } dis[1]=0; shan.push(make_pair(0,1)); while(!shan.empty()) { int xx=shan.top().second; shan.pop(); if(vis[xx]) continue; vis[xx]=1; for(register int i=head[xx];i;i=e[i].net) { int v=e[i].to; if(e[i].liu<li) continue; if(dis[v]>dis[xx]+e[i].val) { dis[v]=dis[xx]+e[i].val; shan.push(make_pair(-dis[v],v)); } } } } int main() { scanf("%d%d%d",&n,&m,&x); for(register int i=1;i<=m;i++) { scanf("%d%d%d%d",&u,&v,&w,&c); flag[i]=c; add(u,v,w,c); add(v,u,w,c); } for(register int i=1;i<=m;i++) { dijkstra(flag[i]); if(dis[n]!=20050206) ans=min(ans,dis[n]+x/flag[i]); } printf("%d",ans); return 0; }
自认为讲得仍是很详细的,若是还有什么不懂的欢迎留言qwq
最后,感谢一下RHL大佬对个人指导