zoukankan      html  css  js  c++  java
  • [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);
    }
  • 相关阅读:
    Kubernetes 集成研发笔记
    Rust 1.44.0 发布
    Rust 1.43.0 发布
    PAT 甲级 1108 Finding Average (20分)
    PAT 甲级 1107 Social Clusters (30分)(并查集)
    PAT 甲级 1106 Lowest Price in Supply Chain (25分) (bfs)
    PAT 甲级 1105 Spiral Matrix (25分)(螺旋矩阵,简单模拟)
    PAT 甲级 1104 Sum of Number Segments (20分)(有坑,int *int 可能会溢出)
    java 多线程 26 : 线程池
    OpenCV_Python —— (4)形态学操作
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4660841.html
Copyright © 2011-2022 走看看