【bzoj2654】tree MST+二分法

来源:互联网 发布:js判断只能输入正整数 编辑:程序博客网 时间:2024/05/29 15:14

Description

  给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
  题目保证有解。

Input

  第一行V,E,need分别表示点数,边数和需要的白色边数。
  接下来E行
  每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

Output

  一行表示所求生成树的边权和。

Sample Input

2 2 10 1 1 10 1 2 0

Sample Output

2

HINT

数据规模和约定

  0:V<=10

  1,2,3:V<=15

  0,..,19:V<=50000,E<=100000

  所有数据边权为[1,100]中的正整数。

Source


CLJ的题 Orz

很奇妙的二分…若给白边加上一个值,则做MST的话选取白边数量不增。

那样就二分这个值,看看选取白边数量,做MST就行了…

还有就是cmp的写法,同边权优先取白边。这样若白边边权+mid则比need小,+mid+1则比need大,则说明同边权既有白边又有黑边,白边可以换成黑边。这样得到的白边数量>=mid则可以更新答案。

#include<cstdio>#include<iostream> #include<cstring>#include<algorithm>using namespace std;const int SZ = 1000010;const int INF = 1000000010;int n,m,nd;struct edge{    int f,t,d,c;}l[SZ];bool cmp(edge a,edge b){    return a.d == b.d ? a.c < b.c : a.d < b.d;}int fa[SZ];int find(int x){    return x == fa[x] ? x : fa[x] = find(fa[x]);}int mst = 0;int MST(int mid){    for(int i = 1;i <= n;i ++) fa[i] = i;    for(int i = 1;i <= m;i ++)        if(!l[i].c) l[i].d += mid;    mst = 0;    int ans = 0;    sort(l + 1,l + 1 + m,cmp);    for(int i = 1;i <= m;i ++)    {        int x = find(l[i].f);        int y = find(l[i].t);        if(x != y)        {            if(!l[i].c) ans ++;            mst += l[i].d;            fa[x] = y;        }    }    for(int i = 1;i <= m;i ++)        if(!l[i].c) l[i].d -= mid;      return ans;}int div(){    int s = -110,t = 110,ans;    while(t - s > 1)    {        int mid = (s + t) >> 1;        int tmp = MST(mid);    //  cout<<mst<<endl;        if(tmp >= nd) s = mid,ans = mst - mid * nd;        else t = mid;     }//  printf("%d %d\n",s,t);    return ans;}int main(){    scanf("%d%d%d",&n,&m,&nd);    for(int i = 1;i <= m;i ++)    {        scanf("%d%d%d%d",&l[i].f,&l[i].t,&l[i].d,&l[i].c);        l[i].f ++;  l[i].t ++;    }    printf("%d",div());    return 0;}
0 0
原创粉丝点击