G. 铁路修复计划 最小生成树

G. 铁路修复计划

二分答案,改变边的权值,找最小生成树即可。

类似的思想还可以用在单度限制最小生成树和最优比例生成树上。

#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef long long int LL;
double k;
int n,m;double M;
struct edge
{
 int from;int to;
 LL cost;int foreign;	
 bool operator <(const edge &b)const
 {
  return (cost+foreign*(k-1.)*cost)<(b.cost+b.foreign*(k-1.)*b.cost);
 }
};
const int maxn=100000+5;
edge e[maxn];
int belong[maxn];
int be(int x)
{
 if(x==belong[x])return x;
 	else return belong[x]=be(belong[x]);
}
bool ex(double mid)
{
 k=mid;
 sort(e,e+m);
 for(int i=1;i<=n;i++)belong[i]=i;
 double ansnow=0;
 for(int i=0;i<m&&ansnow<=M;i++)
 	{
 	 
 	 int u=e[i].from,v=e[i].to;
 	 u=be(u);v=be(v);
 	 //cout<<"ll"<<u<<v<<endl;
 	 if(u!=v){ansnow+=(e[i].cost+e[i].foreign*(k-1.)*e[i].cost),belong[v]=u;}
 	 //cout<<ansnow<<endl;
	}
 return ansnow<=M;
}
int main()
{
// freopen("t.txt","r",stdin);
 LL MM;
 scanf("%d%d%lld",&n,&m,&MM);
 M=(double)MM;
 //cout<<M<<endl;
 for(int i=0;i<m;i++)
 	scanf("%d%d%d%d",&e[i].from,&e[i].to,&e[i].cost,&e[i].foreign);
 double l=1.0,r=1e+15;
 while((r-l)>1e-8)
 	{
 	 //cout<<"double"<<l<<"  "<<r<<endl;
 	 double mid=(r+l)/2.;
 	 if(ex(mid))l=mid;
 	 	else r=mid;
	}
 printf("%.6lf",(l+r)/2.);
 return 0;
}

  

原文地址:https://www.cnblogs.com/heisenberg-/p/6847530.html