BZOJ1196: [HNOI2006]公路修建问题

【传送门:BZOJ1196


简要题意:

  给出n个点,m-1条边,还有一个约束条件k,每条边可以是一级也可以是二级,一级或二级都需要费用,而一级的费用更高,选出n-1条边将n个点连起来,并且n-1条边中要有不少于k条一级边,求出能满足要求的图的最大边的最小值


题解:

  二分+最小生成树判断

  先二分最小值

  然后因为一级的费用总是比二级的高,所以只要有这条边一级的费用≤最小值就选一级边,不选二级边

  否则如果这条边一级的费用>最小值≥二级边就连二级边

  然后在最小生成树的时候统计有多少条一级边,最后进行判断即可


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct cc
{
    int x,y,c1,c2;
}s[21000];
struct node
{
    int x,y,d;
}a[21000];int len;
int fa[11000];
int n,m,k;
int findfa(int x)
{
    if(x!=fa[x]) fa[x]=findfa(fa[x]);
    return fa[x];
}
bool cmp(node n1,node n2)
{
    return n1.d<n2.d;
}
bool check(int x)
{
    len=0;
    for(int i=1;i<=m;i++)
    {
        if(s[i].c1<=x)
        {
            len++;
            a[len].x=s[i].x;a[len].y=s[i].y;a[len].d=0;
        }
        else if(s[i].c2<=x)
        {
            len++;
            a[len].x=s[i].x;a[len].y=s[i].y;a[len].d=1;
        }
    }
    if(len<n-1) return false;
    for(int i=1;i<=n;i++) fa[i]=i;
    int ans=0,tot=0;
    sort(a+1,a+len+1,cmp);
    for(int i=1;i<=len;i++)
    {
        int fx=findfa(a[i].x),fy=findfa(a[i].y);
        if(fx!=fy)
        {
            fa[fx]=fy;
            ans+=a[i].d;
            tot++;if(tot==n-1) break;
        }
    }
    if(tot<n-1) return false;
    if(tot-ans<k) return false;
    else return true;
}
int main()
{
    scanf("%d%d%d",&n,&k,&m);m--;
    for(int i=1;i<=m;i++) scanf("%d%d%d%d",&s[i].x,&s[i].y,&s[i].c1,&s[i].c2);
    int l=0,r=30000,mid,ans;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(check(mid)==true)
        {
            ans=mid;
            r=mid-1;
        }
        else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-03-07 20:22  Star_Feel  阅读(159)  评论(0编辑  收藏  举报