• [BZOJ2654] tree


    2654: tree

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 610  Solved: 225
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    Sample Input

    2 2 1
    0 1 1 1
    0 1 2 0


    Sample Output

    2

    HINT

    数据规模和约定

      0:V<=10

      1,2,3:V<=15

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

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

    Source

    只想说好巧妙地想法……

    对于每条白边,我们每次给他加一个值x(x∈[-101,101],因为所有边权都在这个范围之内),易看出随着x的增大,白边在MST中的数量是渐渐减少的,我们求出每条白边+x时MST中白边的最大数量,因此求出第一个小于need的x,x-1就是我们需要的x,求出此时的MST,即要求的答案。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<queue>
    using namespace std;
    struct node
    {
        int u,v,w,c;
    } e[100005];
    int u[100005],v[100005],w[100005],c[100005],f[50005];
    int n,m,need,ans,sum,cnt,l,r;
    int find(int x) { return x==f[x]?x:f[x]=find(f[x]); }
    bool cmp(node a,node b)
    {
        return ((a.w<b.w)||((a.w==b.w)&&(a.c<b.c)));
    }
    bool pd(int x)
    {
        ans=0;cnt=0;
        for (int i=1;i<=n;i++) f[i]=i;
        for (int i=1;i<=m;i++)
        {
            e[i].u=u[i],e[i].v=v[i],e[i].w=w[i];e[i].c=c[i];
            if(!c[i])e[i].w+=x;
        }
        sort(e+1,e+m+1,cmp);
        for (int i=1;i<=m;i++)
        {
            int p=find(e[i].u),q=find(e[i].v);
            if (p!=q)
            {
                f[p]=q;
                ans+=e[i].w;
                if (e[i].c==0) cnt++;
            }
        }
        return cnt>=need;
    }        
    int main()
    {
        scanf("%d%d%d",&n,&m,&need);
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&u[i],&v[i],&w[i],&c[i]);
            u[i]++; v[i]++;
        }
        l=-101; r=101;
        while (l<=r)
        {
            int mid=(l+r)/2;
            if (pd(mid))
            {
                l=mid+1;
                sum=ans-need*mid;
            }
            else r=mid-1;
        }
        printf("%d",sum);
    }
  • 相关阅读:
    Ajax调用处理页面错误信息500的解决思路
    PHP数据库的增删改
    PHP登录及处理
    PHP数据访问
    PHP数组(正则表达式、数组、预定义数组)
    php函数
    45
    数据库_CRUD操作之读取数据之高级读取
    数据库_CRUD操作之读取数据
    数据库_CRUD操作之修改数据
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4660841.html
Copyright © 2020-2023  润新知