码迷,mamicode.com
首页 > 其他好文 > 详细

Tree

时间:2019-11-04 21:28:50      阅读:118      评论:0      收藏:0      [点我收藏+]

标签:return   main   tps   acp   check   方案   using   col   amp   

https://loj.ac/problem/10069

题目描述

??给出一张图,每条边除边权外还有颜色(黑白两色),求最小权的恰有\(need\)条白边的生成树。

思路

??直接求最小生成树再不断删边和加边使得生成树恰有\(need\)条边且仍是最小权很难维护,我们可以考虑把所有白边都加上一个值,再求一遍最小生成树,可以证明这样必定可以有一种方案可以使一种求出的最小生成树恰有\(need\)条白边,这样就实现对白边数量的调节,而对于这个值我们可以进行二分。

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN=5e4+10,MAXM=1e5+10;
struct Edge
{
    int s,t,c,col;
}e[MAXM];
int fa[MAXN],m,sum,n,need;
bool cmp(Edge x,Edge y)
{    
    if(x.c==y.c)return x.col<y.col;
    else return x.c<y.c;
}
int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
bool check(int k)
{
    for(int i=1;i<=m;i++)
        if(!e[i].col)e[i].c+=k;
    for(int i=0;i<n;i++)
        fa[i]=i;
    sort(e+1,e+m+1,cmp);
//    for(int i=1;i<=m;i++)
//        printf("%d %d\n",i,e[i].c);
    int cnt=0,s=0;
    sum=0;
    for(int i=1;i<=m;i++)
    {
        int fx=find(e[i].s),fy=find(e[i].t);
        if(fx!=fy)
        {
            fa[fx]=fy;
            cnt++;
            sum+=e[i].c;
            if(!e[i].col)s++;
            if(cnt==n-1)break ;
        }
    }
//    cout<<k<<' '<<sum<<' '<<s<<endl;
    for(int i=1;i<=m;i++)
        if(!e[i].col)e[i].c-=k;
    return s>=need;
}
int main() 
{
    scanf("%d%d%d",&n,&m,&need);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d%d",&e[i].s,&e[i].t,&e[i].c,&e[i].col);
    int l=-10000,r=10000,ans;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid))
        {
            ans=sum-need*mid;
            l=mid+1;
        }
        else r=mid-1;
//        cout<<sum<<endl;
    }
    printf("%d",ans);
    return 0;
}

Tree

标签:return   main   tps   acp   check   方案   using   col   amp   

原文地址:https://www.cnblogs.com/fangbozhen/p/11794894.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!