zoukankan      html  css  js  c++  java
  • POJ3621 Sightseeing Cows 和 CH6B12 最优高铁环 和 SCOI2014 方伯伯运椰子

    Sightseeing Cows

    给定一个n(2 <= n <= 1000)个点,m(2 <= m <= 5000)条边的有向图,给定每个点的点值f(i)和每条边的权值w(i),求一个环使得路径上点权和除以边权和最大。

    简单来说就是最优比率生成环。

    题解

    01分数规划问题,按套路二分答案。

    现在问题转化为了判断可行。把边权变成(mid*T-F),这样可行的话一个环的和<0,问题转化成了判断负环。

    而如何判断负环呢?可以记录入队次数,也可以记录最短路边数。而后一种效率更高。

    时间复杂度(O(nmlog v))

    co int N=1e3+1,M=5e3+1;
    co double eps=1e-6;
    int n,m,c[N],f[N],x[M],y[M],z[M];
    int Head[N],Edge[M],Next[M],tot;
    double Leng[M],d[N];
    bool v[N];
    
    il void add(int x,int y,double z){
    	Edge[++tot]=y,Leng[tot]=z,Next[tot]=Head[x],Head[x]=tot;
    }
    bool judge(double w){
    	tot=0,memset(Head,0,sizeof Head);
    	for(int i=1;i<=m;++i) add(x[i],y[i],w*z[i]-f[x[i]]);
    	queue<int> q;
    	for(int i=1;i<=n;++i) q.push(i),d[i]=0,v[i]=1;
    	memset(c,0,sizeof c);
    	while(q.size()){
    		int x=q.front();q.pop();
    		v[x]=0;
    		for(int i=Head[x];i;i=Next[i]){
    			int y=Edge[i];
    			if(d[y]>d[x]+Leng[i]){
    				d[y]=d[x]+Leng[i];
    				if((c[y]=c[x]+1)>=n) return 1;
    				if(!v[y]) q.push(y),v[y]=1;
    			}
    		}
    	}
    	return 0;
    }
    int main(){
    	read(n),read(m);
    	for(int i=1;i<=n;++i) read(f[i]);
    	for(int i=1;i<=m;++i) read(x[i]),read(y[i]),read(z[i]);
    	double l=0,r=1000;
    	while(r-l>eps){
    		double mid=(l+r)/2;
    		if(judge(mid)) l=mid;
    		else r=mid;
    	}
    	printf("%.2f",l);
    	return 0;
    }
    

    背景

    幻影国建成了当今世界上最先进的高铁,该国高铁分为以下几类:
    S---高速光子动力列车---时速1000km/h
    G---高速动车---时速500km/h
    D---动车组---时速300km/h
    T---特快---时速200km/h
    K---快速---时速150km/h
    该国列车车次标号由上述字母开头,后面跟着一个正整数(<=1000)构成。

    描述

    由于该国地形起伏不平,各地铁路的适宜运行速度不同。因此该国的每一条行车路线都由K列车次构成。例如:K=5的一条路线为:T120-D135-S1-G12-K856。当某一条路线的末尾车次与另一条路线的开头车次相同时,这两条路线可以连接起来变为一条更长的行车路线。显然若干条路线连接起来有可能构成一个环。

    若有3条行车路线分别为:
    x1-x2-x3
    x3-x4
    x4-x5-x1
    x1~x5车次的速度分别为v1~v5
    定义高铁环的值为(环上各条行车路线速度和)的平均值,即:
    [(v1+v2+v3)+(v3+v4)+(v4+v5+v1)]/3.
    所有高铁环的值的最大值称为最优高铁环的值。
    给出M条行车路线,求最优高铁环的值。

    输入格式

    第一行为行车路线条数M
    接下来M行每行一条行车路线,由若干车次构成,各车次之间用'-'号隔开,车次的标号方式如上所述。
    数据保证输入的合法性。

    输出格式

    最优高铁环的值。四舍五入到最接近的整数。
    若不存在这样的环,输出-1.

    样例输入

    3
    T120-D135-S1
    S1-G12
    G12-K856-T120

    样例输出

    1283

    数据范围与约定

    • 50%的数据:0<M<=1000
      100%的数据,0<M<=50000
      每条行车路线车次个数不超过20,数据保证结果不超过2^31-1。

    样例解释

    [(200+300+1000)+(1000+500)+(500+150+200)]/3=1283

    题解

    把每段行车路线的起点终点车次看成节点,则给出的就是一些边,然后要求一个01分数规划问题。

    二分答案后,找负(正)环即可。

    co int N=5e4+1;
    co double eps=1e-3;
    int n,m,st,ed,t;
    int head[N],edge[N],next[N],tot;
    double d[N],s[N],leng[N];
    bool v[N];
    
    il void add(int x,int y){
    	edge[++tot]=y,next[tot]=head[x],head[x]=tot;
    }
    il int f(char ch){
    	switch(ch){
    		case 'S': t=0;return 1000;
    		case 'G': t=1;return 500;
    		case 'D': t=2;return 300;
    		case 'T': t=3;return 200;
    		case 'K': t=4;return 150;
    	}
    	return -1;
    }
    bool dfs(int x){
    	v[x]=1;
    	for(int i=head[x];i;i=next[i]){
    		int y=edge[i];double z=leng[i];
    		if(d[y]>d[x]+z){
    			d[y]=d[x]+z;
    			if(v[y]||dfs(y)) return 1;
    		}
    	}
    	v[x]=0;
    	return 0;
    }
    bool pd(double x){
    	for(int i=1;i<=m;++i) leng[i]=x-s[i];
    	memset(v,0,sizeof v);
    	memset(d,0x3f,sizeof d);
    	for(int i=1;i<N;++i)
    		if(dfs(i)) return 1;
    	return 0;
    }
    int main(){
    	read(m);
    	for(int i=1;i<=m;++i){
    		static char str[150];
    		scanf("%s",str),n=strlen(str);
    		int x=0;
    		bool flag=0;
    		for(int j=0;j<n;++j){
    			if(isdigit(str[j])) x=x*10+str[j]-'0';
    			else if(str[j]=='-'){
    				if(!flag) st=x+t*10000;
    				flag=1;
    				x=0;
    			}
    			else s[i]+=f(str[j]);
    		}
    		ed=x+t*10000;
    		add(st,ed);
    	}
    	double l=0,r=0x7fffffff,ans=-1; // edit 1: -1
    	while(r-l>eps){
    		double mid=(l+r)/2;
    		if(pd(mid)) l=ans=mid;
    		else r=mid;
    	}
    	printf("%.0lf
    ",ans);
    	return 0;
    }
    

    方伯伯运椰子

    四川的方伯伯为了致富,决定引进海南的椰子树。方伯伯的椰子园十分现代化,椰子园中有一套独特的交通系统。

    现在用点来表示交通节点,边来表示道路。这样,方伯伯的椰子园就可以看作一个有 (n + 2) 个交通节点,(m) 条边的有向无环图。(n +1) 号点为入口,(n +2) 号点为出口。每条道路都有六个参数,(u_i, v_i, a_i, b_i, c_i, d_i),分别表示,该道路从 (u_i) 号点通向 (v_i) 号点,将它的容量压缩一次要 (a_i) 的花费,容量扩大一次要 (b_i) 的花费,该条道路当前的运输容量上限为 (c_i),并且每单位运输量通过该道路要 (d_i) 的费用。

    在这个交通网络中,只有一条道路与起点相连。因为弄坏了这条道路就会导致整个交通网络瘫痪,聪明的方伯伯决定绝不对这条道路进行调整,也就是说,现在除了这条道路之外,对其余道路都可以进行调整。

    有两种调整方式:

    1. 选择一条道路,将其进行一次压缩,这条道路的容量会下降 1 单位。
    2. 选择一条道路,将其进行一次扩容,这条道路的容量会上升 1 单位。

    一条道路可以被多次调整。

    由于很久以前,方伯伯就请过一个工程师,对这个交通网络进行过一次大的优化调整。所以现在所有的道路都被完全的利用起来了,即每条道路的负荷都是满的(每条道路的流量等于其容量)。但方伯伯一想到自己的海南椰子会大丰收,就十分担心巨大的运输量下,会导致过多的花费。因此,方伯伯决定至少进行一次调整,调整之后,必须要保持每条道路满负荷,且总交通量不会减少。

    设调整后的总费用是 (Y),调整之前的总费用是 (X)。现在方伯伯想知道,最优调整比率是多少,即假设他进行了 (k) 次调整,((X - Y)/k) 最大能是多少?

    注:总费用 = 交通网络的运输花费 + 调整的花费

    对于所有数据,(1 leq N leq 5000, 0 leq M leq 3000, 1 leq U_i,V_i leq N+2, 0 leq A_i,B_i leq 500, 0 leq C_i leq 10000, 0 leq D_i leq 1000)

    题解

    一个可以增容和减容的网络流图?

    由于要满流,所以减容操作的花费是(a_i-d_i),增容操作的花费是(b_i+d_i)

    01分数规划,二分答案( ext{mid})

    起点出边不能变,所以总流量不会变。那么增加的流量和减少的流量抵消了。

    有向无环图,所以改的应该是个“环”?(Y-X+kcdot ext{mid}leq 0),所以找的应该是负环。

    负环要把所有点都放进去……

    CO int N=5e3+10;
    CO float128 inf=1e18;
    struct edge {int y,w;};
    vector<edge> to[N];
    float128 dis[N];
    int vis[N],cnt[N];
    
    int main(){
    	int n=read<int>();
    	for(int m=read<int>();m--;){
    		int x=read<int>(),y=read<int>();
    		int a=read<int>(),b=read<int>(),c=read<int>(),d=read<int>();
    		to[x].push_back({y,b+d});
    		if(c) to[y].push_back({x,a-d});
    	}
    	float128 L=0,R=1e9;
    	for(int t=1;t<=40;++t){
    		float128 mid=(L+R)/2;
    		function<bool()> check=[&]()->bool{
    			deque<int> que;
    			for(int i=1;i<=n+2;++i){
    				dis[i]=0,cnt[i]=0;
    				que.push_back(i),vis[i]=1;
    			}
    			while(que.size()){
    				int x=que.front();
    				que.pop_front(),vis[x]=0;
    				for(CO edge&e:to[x])if(dis[e.y]>dis[x]+e.w+mid){
    					dis[e.y]=dis[x]+e.w+mid;
    					if((cnt[e.y]=cnt[x]+1)>=n) return 1;
    					if(!vis[e.y]) que.push_back(e.y),vis[e.y]=1;
    				}
    			}
    			return 0;
    		};
    		check()?L=mid:R=mid;
    	}
    	printf("%.2Lf
    ",L);
    	return 0;
    }
    
  • 相关阅读:
    ORA-01861: 文字与格式字符串不匹配
    Tomcat启动失败Unrecognized Windows Sockets error: 0: JVM_Bind
    登陆数据库,界面一直保持正在登陆的状态,oracle使用界面无法登陆
    java.sql.SQLException: 关闭的连接
    如何提高家庭宽带的网速?
    打爆IPv4的不一定是IPv6,可能是中国互联网!
    LibreOffice 7.0.1 发布,开源办公套件
    iPhone12系列售价曝光
    TikTok正式起诉特朗普政府
    WordPress主题ripro 6.6
  • 原文地址:https://www.cnblogs.com/autoint/p/10944348.html
Copyright © 2011-2022 走看看