zoukankan      html  css  js  c++  java
  • BZOJ 2654 tree

    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 le 10)
    (1,2,3:V le 15)
    (0,...,19:V le 50000,E le 100000)
    所有数据边权为([1,100])中的正整数。

    我听lyp说,这题是clj出的。lyp讲课的时候把这题作为例题跟我们讲解。
    其实做法很简单,二分一个值(mid),然后将所有白边的边权都减去(mid)再来做最小生成树。但是就是很难YY出来。
    代码有细节需要处理,如果处理不好,可以参考参考我写的程序。

    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    
    #define maxn (100010)
    int V,E,need,father[maxn],ans;
    struct EDGE
    {
    	int s,t,c,col;
    	inline void read() { scanf("%d %d %d %d",&s,&t,&c,&col); ++s; ++t; }
    	inline EDGE dec(int k) { if (col) return *this; return (EDGE){s,t,c-k,col}; }
    	friend inline bool operator <(const EDGE &x,const EDGE &y) { return x.c != y.c?x.c < y.c:x.col < y.col; }
    }bac[maxn],edge[maxn];
    
    inline int find(int a) { if (father[a] != a) father[a] = find(father[a]); return father[a]; }
    
    inline void init() { for (int i = 1;i <= V;++i) father[i] = i; }
    
    inline bool check(int key)
    {
    	for (int i = 1;i <= E;++i) edge[i] = bac[i].dec(key);
    	sort(edge+1,edge+E+1);
    	int cnt = 0,tot = 0,sum = 0;
    	init();
    	for (int i = 1;i <= E;++i)
    	{
    		int r1 = find(edge[i].s),r2 = find(edge[i].t);
    		if (r1 != r2)
    		{
    			++cnt; tot += edge[i].col == 0; sum += edge[i].c;
    			father[r1] = r2;
    		}
    		if (cnt == V-1) break;
    	}
    	if (tot == need) printf("%d",sum+key*need),exit(0);
    	else if (tot < need) return false;
    	ans = sum+key*need;
    	return true;
    }
    
    int main()
    {
    	freopen("2654.in","r",stdin);
    	freopen("2654.out","w",stdout);
    	scanf("%d %d %d",&V,&E,&need);
    	for (int i = 1;i <= E;++i) bac[i].read();	
    	int l = -110,r = 110,mid;
    	while (l <= r)
    	{
    		mid = (l + r) >> 1;
    		if (check(mid)) r = mid - 1;
    		else l = mid + 1;
    	}
    	printf("%d",ans);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    Git——快速安装Git及初始化配置【二】
    Git——Git的简单介绍【一】
    web scraper——简单的爬取数据【二】
    web scraper——安装【一】
    PHP——实现随机打乱一个二维数组
    Vue——显示微信用户名称中enjoin表情
    Vue——轻松实现vue底部点击加载更多
    微信报错——10003
    Java_myBatis_逆向工程
    Java_myBatis_XML代理_动态SQL
  • 原文地址:https://www.cnblogs.com/mmlz/p/4314929.html
Copyright © 2011-2022 走看看