Codeforces 1337C - Linova and Kingdom(树/DFS/BFS/贪心)

   题意:
   一开始所有点都是花园
  1为首都(即根)
  现在n个点里弄k个工厂,而密探都在工厂点上
  密探回首都时每经过一个花园时幸福度+1
  密探一定走最短路
  问最大幸福度之和

  思路:BFS求出每个节点的深度,然后再减掉每个节点儿子所做的贡献,思路在代码中(DFS更简单)
  
  代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <string>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>
#define Fbo friend bool operator < (node a, node b)
#define mem(a, b) memset(a, b, sizeof(a))
#define FOR(a, b, c) for (int a = b; a <= c; a++)
#define RFOR(a, b, c) for (int a = b; a >= c; a--)
#define off ios::sync_with_stdio(0)
#define sc(a) scanf("%d",&a)
#define pr(a) printf("%d\n",a);
#define SC(n,m) scanf("%d%d",&n,&m)
bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; }

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;//1e10
const int mod = 1e9 + 7;
const int Maxn = 1e5 + 5;
const int N = 2e5 + 5;
const double pi = acos(-1.0);
const double eps = 1e-8;

struct node {
    ll b;//深度
    ll id;//位置
}h[N];

vector<ll>G[N];
ll n, k, u, v;
ll vis[N];
ll cnt[N];
ll dis[N];
bool cmp(const node& a, const node& b)
{
    return a.b > b.b;
}
int main()
{
    cin >> n >> k;
    FOR(i, 1, n - 1)
    {
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u); //首先建图
    }
    memset(vis, 0, sizeof(vis));
    h[1].b = 0;
    FOR(i, 1, n){
        h[i].id = i;//将每个点标号
        cnt[i] = 1;//每个节点初始贡献为1
    }
    vis[1] = 1;
    queue<ll>q;
    q.push(1);
    while (!q.empty())
    {
        ll start = q.front();
        q.pop();
        for (int i = 0; i < G[start].size(); i++)
        {
            if (!vis[G[start][i]])
            {
                vis[G[start][i]] = 1;
                h[G[start][i]].b = h[start].b + 1; //得到每个点的深度
                q.push(G[start][i]);
            }
        }
    }
    FOR(i, 1, n) dis[i] = h[i].b; //dis[i]存每个点的深度
    sort(h + 1, h + n + 1, cmp);//从深度最大的节点往下从大到小排
    for (int i = 1; i <= n; i++){
        int now = h[i].id;//表示当前的节点
        for (int j = 0; j < G[now].size(); j++) //查看当前的节点是否有儿子
        {
            if (dis[G[now][j]] > dis[now]) //如果有并且当前儿子节点的深度 > 父亲节点的深度
                cnt[now] += cnt[G[now][j]];  //计算该节点的儿子们所做的贡献 cnt[i]初始值为1
        }
        h[i].b -= (cnt[now] - 1); //减去儿子后面要做的贡献,记得减去1本身
    }
    sort(h + 1, h + n + 1, cmp); //贪心从深度最深的点开始加
    ll ans = 0;
    FOR(i, 1, k){
        ans += h[i].b;
    }
    cout << ans << endl;
}

 

猜你喜欢

转载自www.cnblogs.com/AlexLINS/p/12711788.html