zoukankan      html  css  js  c++  java
  • Milk Pumping G&Milk Routing S

    Milk Pumping G&Milk Routing S

    双倍经验时间

    洛谷P5837 [USACO19DEC]Milk Pumping G

    洛谷P3063 [USACO12DEC]Milk Routing S

    题目模型

    给定(N)个点和(M)条边,对于每条边,给定连接的两个端点以及这条边的花费和“流量”

    1. 设这条路径上所有边的花费总和为(L)

    2. 设这条路径上所有边中“流量”值最小的为(C)

    要求找出一条(1)(N)的路径满足:(L)尽可能小的同时(C)尽可能大(注意是一条路径上的L和C)


    解题思路

    如果是单独求(L)或者(C)中的一个,那么我们很容易便能解决

    但是如果要求同时维护(L)(C)两个值,而且这两个值还是矛盾的,那我们怎么做呢?

    (这里的矛盾指:(L)要尽量小,而同一条道路的(C)又要尽量大)

    • First

    首先我们先来考虑用一个最短路同时维护这两个值,但经过一番思索,我们会发现无法做到

    为什么?因为这两个值矛盾啊!相矛盾的两个值怎么能在同一个最短路中解决呢?

    • Second

    否定了同时维护的想法,我们只能考虑分开维护,分开维护?多个最短路?

    肯定也不行,为什么?维护出来的(L)(C)分别对应的最短路径不一定是同一条啊!最短路径都不是同一条那(L)(C)怎么会相对应呢?

    • Third

    同时维护和分开维护都不行,那怎么做?

    枚举

    什么意思?

    我们要维护对应的两个值,那我们可以枚举其中一个值,然后再在枚举的这个值的基础上去寻找对应的另一个值呀!

    怎么实现呢?

    假设我们枚举(Ci),然后跑最短路去求解对应的(Li),在跑最短路时判断当前点(v)(Cv)值是否小于(Ci),如果小于那么就不管这个点(因为我们枚举的(Ci)已经是假定的最小流量值,那么所有小于(Ci)肯定没有用)

    为什么(Ci)是假定的最小流量值?不是求最大的(C)吗?

    我们不断枚举(Ci),找到所有对应的(Li),然后用一个(ans)来记录最终的答案,最终找到的一定是最大的(C)和最小的(L)


    代码Code

    #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大佬对我的指导


  • 相关阅读:
    java匿名内部类
    【绝对给力】Android开发免豆资料(教程+工具+源码)地址汇总
    【绝对给力】Android开发免豆资料(教程+工具+源码)地址汇总
    【分享】Java学习之路:不走弯路,就是捷径
    【分享】熟练的Java程序员应该掌握哪些技术?
    【分享】熟练的Java程序员应该掌握哪些技术?
    android 小知识点
    android 小知识点
    Eclipse快捷键大全
    Eclipse快捷键大全
  • 原文地址:https://www.cnblogs.com/Eleven-Qian-Shan/p/13207029.html
Copyright © 2011-2022 走看看