• 【训练题】最优比率生成树 P1696


    Description

    FJ最近从政府获得开发N块废弃牧区的许可,但这些牧区之间没有道路,FJ打算先修建一些道路,便于他的奶牛们能自由地从一个牧区到达另一个牧区。


    经过细致考察,FJ告诉你牧区i与牧区j之间的距离d[i]j以及修这条道路的花费c[i][j]元。现在请你帮助FJ规划应怎样修建道路才能使每公里的花费最少。


    Input

    第1行:2个用空格隔开的整数:N和M。接下来的M行,每行四个正整数:x,y,d,c,分别表示牧区x和牧区y之间的距离为d,花费为c。


    Output

    输出FJ修建道路单位公里的最小花费,保留2位小数。


    Hint

    N<=400,M<=10000


    Solution

    emmmmm……首先这道题求的是平均的单位公里的花费(就是从花费除以总公里数)而不是修每段路的单位公里数,所以要二分猜答案。然后需要明确的就是每次check的时候每条边的边权要处理成什么。关系式:edge[i].w=(double)edge[i].c-(double)edge[i].d*mid;如果是符合条件的mid的话,这棵最小生成树的边权和应该等于0(当然,涉及到精度问题,可能判断的时候用1e-6要好些吧。。。。虽然我用0还是过了嘻嘻)。


    注意事项:
    1.check的时候判断的是边权和而不是最大边权,所以ans应该+=而不是=,因为mid表示的是一个平均值而不是最大值。
    2.每次check之前ans要清零。
    3.啊,我也不知道还能说什么了。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define maxn 20005
    using namespace std;
    struct Edge{
    	int u;
    	int v;
    	int d;
    	int c;
    	double w;
    	int next;
    	friend bool operator < (Edge a,Edge b){
    		return a.w<b.w;
    	}
    }edge[maxn];
    int first[maxn],last[maxn],FA[maxn];
    int node,x,y,z,c,n,m,cnt;
    double L,R,mid,ans;
    void addedge(int u,int v,int d,int c){
    	edge[++node]=(Edge){u,v,d,c,0,0};
    	if(first[u]==0)first[u]=node;
    	else edge[last[u]].next=node;
    	last[u]=node;
    }
    void init(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++){
    		scanf("%d%d%d%d",&x,&y,&z,&c);
    		addedge(x,y,z,c);
    	}
    }
    int dofind(int x){
    	if(FA[x]==x)return x;
    	return FA[x]=dofind(FA[x]);
    }
    void dounion(int x,int y){
    	int dx=dofind(x),dy=dofind(y);
    	if(dx!=dy){
    		FA[dx]=FA[dy];
    	}
    }
    bool dofinD(int x,int y){
    	return dofind(x)==dofind(y);
    } 
    bool check(double mid){
    	cnt=0;
    	ans=0;
    	for(int i=1;i<=n;i++){
    		FA[i]=i;
    	}
    	for(int i=1;i<=m;i++){
    		edge[i].w=(double)edge[i].c-(double)edge[i].d*mid;
    	}
    	sort(edge+1,edge+m+1);
    	for(int i=1;i<=m;i++){
    		int a=edge[i].u,b=edge[i].v;
    		if(dofinD(a,b))continue;
    		dounion(a,b);
    		ans+=edge[i].w;
    		cnt++;
    		if(cnt==n-1)break;
    	}
    	if(cnt<n-1)return false;
    	if(ans<=0)return true;
    	return false;
    }
    int main(){
    	init();
    	L=0.0,R=10000.0;
    	while(L<=R){
    		mid=(L+R)/2.0;
    		if(!check(mid))L=mid+0.0000001;
    		else R=mid-0.0000001;
    	}
    	printf("%.2lf",mid);
    	return 0;
    }
    
  • 相关阅读:
    没想到吧?这货比 open 更适合读取文件
    卸载 PyCharm!这才是 Python 小白的最理想的 IDE
    git 会保留所有的提交吗?不会!
    C# 在构造函数内调用虚方法
    【转】第一个汇编器是怎么实现的
    SQL Server查询数据库所有表名与表说明
    Vue实现节流,防止重复提交
    mysql 查询json数组(一)
    VScode怎么在代码折叠后,插入新的内容
    Vue 通过调用百度API获取地理位置-经度纬度省份城市
  • 原文地址:https://www.cnblogs.com/virtual-north-Illya/p/10045233.html
Copyright © 2020-2023  润新知