tree
内存限制:512 MiB 时间限制:3000 ms 标准输入输出
题目类型:传统 评测方式:文本比较
题目描述
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。题目保证有解。
输入格式
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
输出格式
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
样例
样例输入
2 2 1
0 1 1 1
0 1 2 0
样例输出
2
数据范围与提示
原数据出错,现已更新 by liutian,但未重测---2016.6.24
也是一个做法比较玄学的题
二分答案,考虑我们往白边上加值或者减值,那么就会对应的少选白边或者少选黑边
那么如果当前 白边+mid如果kuskal选择白边比need多就继续往上面加值,如果选择白边比need少就往下减值
因为kuskal保证图一定连通,并且代价最小。所以保证了正确性
#include<bits/stdc++.h> #define ll long long #define A 10000000 using namespace std; struct edge{ ll x,y,z,id; ll flag; }e[A]; ll n,m,need,fa[A],zong,ans,end[A]; inline ll read() { ll f=1,x=0;char c=getchar(); while(!isdigit(c)){if(c==‘-‘) f=-1;c=getchar();} while(isdigit(c)){x=x*10+c-‘0‘;c=getchar();} return f*x; } ll find(ll x) { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void hebing(ll x,ll y) { x=find(x),y=find(y); if(x!=y) fa[y]=x; } bool cmp(edge a,edge b){return (a.z==b.z)?(a.flag<b.flag):(a.z<b.z);} inline void kuskar(ll mid) { for(ll i=0;i<=n;i++) fa[i]=i; zong=0,ans=0; for(ll i=1;i<=m;i++) if(!e[i].flag) e[i].z+=mid; sort(e+1,e+m+1,cmp); for(ll i=1;i<=m;i++) { if(find(e[i].x)!=find(e[i].y)) { if(!e[i].flag) zong++; hebing(e[i].x,e[i].y); ans+=e[i].z; } } for(ll i=1;i<=m;i++) if(!e[i].flag) e[i].z-=mid; } int main() { ll tot=0; n=read(),m=read(),need=read(); for(ll i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].z=read(),e[i].flag=read(); ll l=-100,r=100; while(l<=r) { ll mid=(l+r)>>1; kuskar(mid); if(zong>=need) l=mid+1,tot=ans-need*mid; else r=mid-1; } cout<<tot<<endl; }
原文地址:https://www.cnblogs.com/znsbc-13/p/11202606.html
时间: 2024-09-30 13:03:47