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;
    }
    
  • 相关阅读:
    POJ 1401 Factorial
    POJ 2407 Relatives(欧拉函数)
    POJ 1730 Perfect Pth Powers(唯一分解定理)
    POJ 2262 Goldbach's Conjecture(Eratosthenes筛法)
    POJ 2551 Ones
    POJ 1163 The Triangle
    POJ 3356 AGTC
    POJ 2192 Zipper
    POJ 1080 Human Gene Functions
    POJ 1159 Palindrome(最长公共子序列)
  • 原文地址:https://www.cnblogs.com/mmlz/p/4314929.html
Copyright © 2011-2022 走看看