div2贪心+建树

C. Linova and Kingdom

Writing light novels is the most important thing in Linova’s life. Last night, Linova dreamed about a fantastic kingdom. She began to write a light novel for the kingdom as soon as she woke up, and of course, she is the queen of it.

There are n cities and n−1 two-way roads connecting pairs of cities in the kingdom. From any city, you can reach any other city by walking through some roads. The cities are numbered from 1 to n, and the city 1 is the capital of the kingdom. So, the kingdom has a tree structure.

As the queen, Linova plans to choose exactly k cities developing industry, while the other cities will develop tourism. The capital also can be either industrial or tourism city.

A meeting is held in the capital once a year. To attend the meeting, each industry city sends an envoy. All envoys will follow the shortest path from the departure city to the capital (which is unique).

Traveling in tourism cities is pleasant. For each envoy, his happiness is equal to the number of tourism cities on his path.

In order to be a queen loved by people, Linova wants to choose k cities which can maximize the sum of happinesses of all envoys. Can you calculate the maximum sum for her?

Input
The first line contains two integers n and k (2≤n≤2⋅105, 1≤k<n) — the number of cities and industry cities respectively.

Each of the next n−1 lines contains two integers u and v (1≤u,v≤n), denoting there is a road connecting city u and city v.

It is guaranteed that from any city, you can reach any other city by the roads.

Output
Print the only line containing a single integer — the maximum possible sum of happinesses of all envoys.

大意:给出n,k和一个点数量为n的树,让其中k个结点变为工业城市,其余为旅游城市。而每个工业城市到根节点1的路径上存在的旅游城市数量之和求最大,并输出最大值。

题目链接:https://codeforces.com/contest/1337/problem/C

解法一:
最大的就是节点一(子儿子为n-1深度为0)
每个旅游城市做出的贡献为:他的子儿子个数减去他的祖先个数(深度个数)
假设它的子儿子都为工厂,则做出的贡献为子儿子个数
因为此时它为旅游区,而之前它的祖先为他做出了贡献,此时它变为了旅游区所以需要减去它祖先的个数
排序,然后有k个工厂则有n-k个旅游城市,选出最大的n-k个旅游城市

#include<bits/stdc++.h>
#define ll long long

using namespace std;

vector<int>G[200001];
ll len[200001];   //高度
int fa[200001];  //父亲节点
ll son[200001]; //子儿子数目
struct lll{
    ll so;
    ll dep;
    int inde;

}ans[200001];
bool cmp(lll &node1,lll &node2){


    return node1.so-node1.dep+1<node2.so-node2.dep+1;  //因为减的是高度所以再+1
}
void dfs(int u,int f,ll step){
    fa[u]=f;
    len[u]=step;
    int n=G[u].size();
    for (int i=0;i<n;i++){
        int v=G[u][i];
        if(v==f) continue;
        dfs(v,u,step+1);
        son[u]+=son[v];
    }

}
int main()
{
    int n,k;
    cin>>n>>k;
    len[0]=0;
    for (int i=0;i<n-1;i++){
        int a,b;
        cin>>a>>b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    son[1]=G[1].size();
    for (int i=2;i<=n;i++){
        son[i]=G[i].size()-1; //子儿子数等于本身儿子 在进行dfs加上孙子
    }
    dfs(1,0,1);
    for (int i=2;i<=n;i++){
       ans[i].so=son[i];
        ans[i].dep=len[i];
        ans[i].inde=i;
    }
        ll sum=n-1;
    sort(ans+2,ans+n+1,cmp);  
    int i=n;
    k=n-k-1;
    while(k){

        sum+=ans[i].so-len[fa[ans[i].inde]];   //加上每个旅游区的贡献
        k--;
        i--;
    }
    cout<<sum;
}

解法2:
总共有k个工厂,假设全为旅游区,每个工厂做出的贡献为它的深度减去它的子孙的个数,因为如果此节点为工厂那么它的子孙都是工厂(可以自行验证),如果它的子孙不是工厂的话就不是最优解。那么这个工厂做出的贡献为它的深度减去它的子孙个数,因为它的祖先是旅游区,则它得到贡献为它的深度,而之前它的子孙接受了它的贡献,而此时变为了工厂,那么要减去这些贡献。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
众所周知,人工智能是当前最热门的话题之一, 计算机技术与互联网技术的快速发展更是将对人工智能的研究推向一个新的高潮。 人工智能是研究模拟和扩展人类智能的理论与方法及其应用的一门新兴技术科学。 作为人工智能核心研究领域之一的机器学习, 其研究动机是为了使计算机系统具有人的学习能力以实现人工智能。 那么, 什么是机器学习呢? 机器学习 (Machine Learning) 是对研究问题进行模型假设,利用计算机从训练数据中学习得到模型参数,并最终对数据进行预测和分析的一门学科。 机器学习的用途 机器学习是一种通用的数据处理技术,其包含了大量的学习算法。不同的学习算法在不同的行业及应用中能够表现出不同的性能和优势。目前,机器学习已成功地应用于下列领域: 互联网领域----语音识别、搜索引擎、语言翻译、垃圾邮件过滤、自然语言处理等 生物领域----基因序列分析、DNA 序列预测、蛋白质结构预测等 自动化领域----人脸识别、无人驾驶技术、图像处理、信号处理等 金融领域----证券市场分析、信用卡欺诈检测等 医学领域----疾病鉴别/诊断、流行病爆发预测等 刑侦领域----潜在犯罪识别与预测、模拟人工智能侦探等 新闻领域----新闻推荐系统等 游戏领域----游戏战略规划等 从上述所列举的应用可知,机器学习正在成为各行各业都会经常使用到的分析工具,尤其是在各领域数据量爆炸的今天,各行业都希望通过数据处理与分析手段,得到数据中有价值的信息,以便明确客户的需求和指引企业的发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值