zoukankan      html  css  js  c++  java
  • 雅礼培训 Problem B 【图论 + 贪心】

    题意##

    A和B在树上轮流选点,记A的联通块个数为(x),B的联通块个数为(y)
    A使(x - y)最大,B使(x - y)
    二人采取最优策略,求(x-y)

    题解##

    树联通块个数 = 点数 - 边数

    有这个转化,我们记二人选的点数为P,联通块内边数为E
    (ans = (P_{A} - E_{A}) - (P_{B} - E_{B}))
    其中(P)的差是固定的
    我们要求的是(E_{A} - E_{B})

    A会使这个值尽量大,会使其选的边尽量少
    B会使这个值尽量小,会使其选的边尽量少

    所以二者都会尽量少地选边

    但二人是直接选点的,考虑将边转为到点上

    当一条边两端颜色相同,则计入对应的贡献,否则不计入贡献
    如果说边权为1的话,我们将一条边的权值分配到两端的点上
    A选就是-1,B选就是1
    这样的话,如果两端的点颜色不同,贡献为0;颜色相同,贡献为对应的值*2

    而这样,每个点的权值就是每个点的度数
    所以我们只需要将度数排序,贪心选择即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u]; k; k = ed[k].nxt)
    using namespace std;
    const int maxn = 100005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
    	return out * flag;
    }
    int de[maxn],n,A,B;
    int main(){
    	n = read();
    	for (int i = 1; i < n; i++){
    		de[read()]++;
    		de[read()]++;
    	}
    	sort(de + 1,de + 1 + n);
    	for (int i = 1; i <= n; i++){
    		if (i & 1) A -= de[i];
    		else B += de[i];
    	}
    	printf("%d
    ",(n & 1) + ((B + A) >> 1));
    	return 0;
    }
    
    
  • 相关阅读:
    关于MQ的对比
    关于RabbitMQ(二)
    关于QPS、TPS、并发用户数、吞吐量的关系
    关于使用Ecplise构建gradle项目
    关于记录一次线上真实环境多线程引发的问题
    关于MySQL——find_in_set()函数的使用
    关于数据库的表连接
    关于Java线程池
    IntelliJ搭建Scala及Spark工程
    idea编写wordcount程序及spark-submit运行
  • 原文地址:https://www.cnblogs.com/Mychael/p/8696503.html
Copyright © 2011-2022 走看看