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; }