BZOJ-2654 tree

2654: tree
题目链接
时间限制: 30 Sec 内存限制: 512 MB
提交: 2782 解决: 1138
题目描述
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
输入
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
输出
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
样例输入
2 2 1

0 1 1 1

0 1 2 0
样例输出
2
提示
原数据出错,现已更新 by liutian,但未重测—2016.6.24

题解
这道题目的想法很棒。

如果白色边边权会变,那么随着这个值的变大,所选白边条数变少。

我们要做的就是控制白边的数量,使得它正好等于need。

由于变化是单调的,所以,我们想到用二分枚举。

如果发现选的白边数≥need,那么L=mid+1。否则R=mid-1。

但是真正把代码写下了,却发现有一种特别的数据过不去:

当前的mid,使得白边数<need,但是mid+1使得白边数>need。

后来看过网上大神的博客才恍然大悟。

完全不用担心,因为题目保证有解,所以肯定是由于顺序的缘故。

也就是说肯定有一些和白边长度相等的黑边,我们可以把多余的白边替换掉。

若没有可替换的黑边,那么mid再大一些是完全可以的。

所以白边数≥need时就把当前的总代价赋给ans。

别忘了,有若干条白边的代价改变了,记得扣回来!

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=5e4+5,maxm=1e5+5;
int n,m,ned,fa[maxn],n1,n2,ans;
struct js{
    int x,y,s;
}blk[maxm],wit[maxm];
int read()
{
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
int get(int x){return (fa[x]==x)?x:fa[x]=get(fa[x]);}
bool cmp(js x,js y){return x.s<y.s;}
int check(int tem)
{
    for (int i=1;i<=n;i++) fa[i]=i;
    int L1=1,L2=1,cnt=0,tot=n-1;
    js nxt;int p=1,sum=0;
    for (int i=1;i<=m;i++)
    {
        if (wit[L2].s+tem<=blk[L1].s) nxt=wit[L2++],p=1;
        else nxt=blk[L1++],p=0;
        int x=get(nxt.x),y=get(nxt.y);
        if (x==y) continue;fa[x]=y;
        sum+=nxt.s+tem*p;cnt+=p;
        if (!(--tot)) break;
    }
    if (cnt>=ned) ans=sum-(LL)ned*tem;
    //最重要的就是-ned*tem,扣回多出代价
    return cnt;
}
int main()
{
    n=read(),m=read();ned=read();
    for (int i=1;i<=m;i++)
    {
        int x=read()+1,y=read()+1,s=read(),c=read();
        if (c) blk[++n1]=(js){x,y,s};
          else wit[++n2]=(js){x,y,s};
    }
    sort(blk+1,blk+n1+1,cmp);
    sort(wit+1,wit+n2+1,cmp);//分成两组,可以避免二分check时多次排序
    blk[++n1].s=1e9;wit[++n2].s=1e9;
    int L=-105,R=105;ans=1e9;
    while (L<=R)
    {
        int mid=(R-L>>1)+L;
        int ask=check(mid);
        if (ask>=ned) L=mid+1;
        else R=mid-1;
    }
    printf("%d",ans);
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xu0_zy/article/details/79980585
上一篇POJ-2513 Colored Sticks
下一篇LG-P1227 [JSOI2008]完美的对称
想对作者说点什么? 我来说一句

checkbox tree extjs

2010年05月09日 981KB 下载

Extjs的tree

2011年05月09日 562KB 下载

C# Tree实验 Tree实验

2010年09月01日 136KB 下载

bootstrap tree

2018年04月08日 234KB 下载

tree, linux 命令

2011年11月15日 42KB 下载

checkbox tree extjs2

2010年05月09日 3.7MB 下载

完美的Tree完美的Tree

2011年04月17日 422KB 下载

treeplan Excel决策树

2018年05月04日 487KB 下载

ext3.0 treeandtabPanel

2011年11月18日 1.12MB 下载

没有更多推荐了,返回首页

关闭
关闭