bzoj2654
Description
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
Input
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
Output
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
Sample Input
2 2 1
0 1 1 1
0 1 2 0
0 1 1 1
0 1 2 0
Sample Output
2
特殊处理边权 最小生成树
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=50000+10,maxm=100000+10; int n,m,nd,fa[maxn],ans; double k; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } struct Node{ int x,y,c;double z; }node[maxm]; int find(int x) { return x==fa[x]? x:fa[x]=find(fa[x]); } bool cmp(const Node& a,const Node& b) { return a.z+k*a.c<b.z+k*b.c; } int rs,tot; int Kr() { ans=0; int a,b; for(int i=1;i<=n;++i) fa[i]=i; for(int i=1;i<=m;++i) { a=find(node[i].x);b=find(node[i].y); if(a!=b) { fa[a]=b; tot++; ans+=node[i].z; rs+=node[i].c; if(tot==n-1) break; } } return rs; } int main() { n=read();m=read();nd=read(); for(int i=1;i<=m;++i) { node[i].x=read()+1;node[i].y=read()+1; node[i].z=read();node[i].c=read()^1; } sort(node+1,node+m+1,cmp); int now;double l=-100,r=100; now=Kr(); while(now!=nd) { if(now>nd) l=k+1;else r=k-1; k=(l+r)/2.0; sort(node+1,node+m+1,cmp); now=Kr(); if(l>=r-0.5) break; } printf("%d",ans); return 0; }
弱者就是会被欺负呀