每日一题之 hiho1779 公路收费

描述
A 国有 n 个城市,第 i 个城市有 ai 个会议代表,这 n 个城市通过 n-1 条双向的高速公路连接,保证每两个城市都可以通过高速公路互相到达,每个人通过一条高速公路都要付相应的费用。

现在 A 国的总统想挑选一个城市作为会议中心,要求全国所有会议代表都到这个城市来,为了方便大家出行,A 国的总统可以让不超过 k 条高速公路的收费变为 0 。

现在你要安排挑选的城市和免费的高速公路,最小化的所有会议代表的路费总和。

输入
第一行两个整数 n, k

第二行 n 个非负整数,第 i 个表示ai

接下来 n-1 行,每行三个整数 u, v, w,描述一条收费为 w 的高速公路 (u, v)

1 ≤ n ≤ 10^3

0 ≤ k ≤ n-1

1 ≤ w, ai≤ 10^5

输出
输出最小的路费总和

样例解释
让 (2,3) 免费,然后选 2 作为会议城市

扫描二维码关注公众号,回复: 2450086 查看本文章

样例输入
3 1
1 2 3
1 2 1
2 3 2
样例输出
1

思路:

要求每个城市的代表到一个城市开会,相当于从图中某个点开始把图遍历一遍,在dfs的过程中记录走过的节点以及节点的人数然后再乘以边权。然后枚举每个点为起点,遍历图,然后删去k条收费最高的边,取一个最小值就是答案。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

const int maxn = 1e3+5;

struct edge
{
    int to;
    long long w;
};

long long e[maxn];
bool visit[maxn];
int A[maxn];
int f[maxn];

vector<edge>E[maxn];

int n,k;

void dfs(int x , long long w)
{
    visit[x] = true;
    for (int i = 0; i < E[x].size(); ++i) {
        int y = E[x][i].to;
        if (visit[y]) continue;
        dfs(y,E[x][i].w);
        f[x] += f[y];
    }
    f[x] += A[x];
    e[x] = w * f[x];
}

long long solve(int x)
{
    memset(f,0,sizeof(f));
    memset(visit,0,sizeof(visit));
    memset(e,0,sizeof(e));

    dfs(x,0);
    swap(e[x],e[n]);
    sort(e+1,e+n);
    long long res = 0;
    for (int i = n-k-1; i >= 1; --i) {
        res += e[i];
    }
    return res;
}

int main()
{
    cin >> n >> k;

    for (int i = 1; i <= n; ++i)
        cin >> A[i];

    int u,v;
    long long w;
    for (int i = 0; i < n-1; ++i) {
        cin >> u >> v >> w;
        edge tmp;
        tmp.to = v;
        tmp.w = w;
        E[u].push_back(tmp);
        tmp.to = u;
        E[v].push_back(tmp);
    }
    long long res = 1e18;
    for (int i = 1; i <= n; ++i)
        res = min(res,solve(i));

    cout << res << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/u014046022/article/details/80993293