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;
    }
    
  • 相关阅读:
    LSMW TIPS
    Schedule agreement and Delfor
    Running VL10 in the background 13 Oct
    analyse idoc by creation date
    New Journey Prepare
    EDI error
    CBSN NEWS
    Listen and Write 18th Feb 2019
    Microsoft iSCSI Software Target 快照管理
    通过 Microsoft iSCSI Software Target 提供存储服务
  • 原文地址:https://www.cnblogs.com/mmlz/p/4314929.html
Copyright © 2011-2022 走看看