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;
}
弱者就是会被欺负呀

浙公网安备 33010602011771号