洛谷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大佬對個人指導