题意
中文题,不解释
题解
原本以为是一道普通的最小生成树问题,但是搞了很久都没办法控制最优选择顺序。后来看了题解才恍然大悟,怎么说呢,感觉很神奇。通过二分搜索去凑解,看似复杂度很高,但是计算一下就会发现复杂度只有O(n*log^2(n)),处于可以接受的范围。
注意事项
一定要注意kruskal算法里的变量要用double,在这里DEBUG了半天。
代码
#include <bits/stdc++.h>
#define INF 10000010
#define MAXN 100010
#define EPS 1e-7
using namespace std;
typedef long long ll;
int n,m;
struct Edge{
int from,to,type;
double weight;
};
bool cmp(Edge a,Edge b){
return a.weight<b.weight;
}
Edge edges[MAXN] ;
int p[MAXN];
void init(){
for(int i=1;i<=n;i++){
p[i]=i;
}
}
int find(int x){
return x==p[x]?x:p[x]=find(p[x]);
}
void unite(int x,int y){
p[find(x)]=find(y);
}
bool same(int x,int y){
return find(x)==find(y);
}
double kurskal(){
sort(edges,edges+m,cmp);
init();
double cost=0;
for(int i=0;i<m;i++){
Edge e=edges[i];
if(!same(e.from,e.to)){
unite(e.from,e.to);
cost+=e.weight;
}
}
return cost;
}
int main()
{
ll M;
scanf("%d%d%lld",&n,&m,&M);
for(int i=0;i<m;i++){
int u,v,t,f;
scanf("%d%d%d%d",&u,&v,&t,&f);
edges[i].from=u;
edges[i].to=v;
edges[i].weight=t;
edges[i].type=f;
}
double low=1,up=(double)M;
double mid=1;
while(up-low>EPS){
mid=(low+up)/2;
for(int i=0;i<m;i++){
if(edges[i].type)
edges[i].weight*=mid;
}
double ans=kurskal();
for(int i=0;i<m;i++){
if(edges[i].type)
edges[i].weight/=mid;
}
if(ans-M>EPS){
up=mid;
}else{
low=mid;
}
}
printf("%lf\n",mid);
}