zoukankan      html  css  js  c++  java
  • BZOJ2654 tree

    给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有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]中的正整数。

    题解
    给白色边都加上一个权值,做mst会使得选取的白边数量减少(但是当黑白边权值一样,应该优先选择白边,因为在当前的设定下,是可以选择出若干条白边满足要求的),所以可以二分这个权值

    #include<iostream>
    #include<set>
    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<ctime>
    #include<vector>
    #include<queue>
    #include<algorithm>
    #include<cmath>
    #define inf 1000000000
    #define pa pair<int,int>
    #define ll long long 
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m,cnt,tot,ned;
    int sumv;
    int u[100005],v[100005],w[100005],c[100005];
    int fa[100005];
    struct edge{
    	int u,v,w,c;
    }e[100005];
    bool operator<(edge a,edge b) //白边尽量放在前面,坑点
    {
    	return a.w==b.w?a.c<b.c:a.w<b.w;
    }
    int find(int x)
    {
    	return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    bool check(int x)
    {
    	tot=cnt=0;
    	for(int i=1;i<=n;i++)
    	    fa[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);
    	for(int i=1;i<=m;i++)
    	{
    		int p=find(e[i].u),q=find(e[i].v);
    		if(p!=q)
    		{
    			fa[p]=q;
    			tot+=e[i].w;
    			if(!e[i].c) //统计白边有多少条 
    			    cnt++;
    		}
    	}
    	return cnt>=ned;
    }
    int main()
    {
    	n=read();m=read();ned=read();
    	for(int i=1;i<=m;i++)
    	{
    		u[i]=read(),v[i]=read(),w[i]=read(),c[i]=read();
    		//w[i]为边权,c[i]为color ,(0白色1黑色)
    		
    		u[i]++;
    		v[i]++;
    	}
    	int l=-105,r=105;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid))
    		    l=mid+1,
    			sumv=tot-ned*mid;//sumv为实际上求出来的mst的代价 
    		else 
    		     r=mid-1;
    	}
    	printf("%d",sumv);
    	return 0;
    }
    

      

  • 相关阅读:
    vue单页应用项目加入百度统计代码
    关于VUE Spa 项目html5-History模式在微信浏览器内IOS和安卓分享的问题
    iphone 上使用contenteditable 输入法无法换行
    javaScript 三目运算符初探
    javaScript for in循环遍历对象
    javaScript 原型与原型链学习笔记
    javaScript call与apply学习笔记
    javaScript 对象学习笔记
    javaScript 立即执行函数学习笔记
    javaScript [[scope]]学习笔记
  • 原文地址:https://www.cnblogs.com/cutemush/p/12464295.html
Copyright © 2011-2022 走看看