Codeforces 986A Fair(最短路)

题目链接

解题思路

  经典的逆向思维,题目数据的特殊性提示我们利用好k只有100的条件。
  每次用bfs把所有编号相同的点作为搜索的起点,根据bfs的性质,每个点第一次被访问的时的距离就是它离起点最近的距离。然后对于每个点,选出前s大即可。

代码

const int maxn = 1e5+10;
struct E {
    int to, nxt;
} e[maxn<<1];
bool vis[maxn];
int h[maxn], a[maxn], d[maxn][105], tot, n, m, k, s;
void add(int a, int b) {
    e[++tot] = {b, h[a]};
    h[a] = tot;
}
vector<int> tp[105];
void solve(int x) {
    for (int i = 1; i<=n; ++i) {
        d[i][x] = INF; vis[i] = false;
    }
    queue<P> qe;
    for (auto u : tp[x]) {
        d[u][x] = 0; qe.push({0, u}); vis[u] = true;
    }
    while(!qe.empty()) {
        int u = qe.front().second, w = qe.front().first; qe.pop();
        ++w;
        for (int i = h[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if (!vis[v]) {
                vis[v] = true;
                qe.push({d[v][x]=w, v});
            }
        }
    }
}
int main(void) {
    scanf("%d%d%d%d", &n, &m, &k, &s);
    for (int i = 1; i<=n; ++i) {
        scanf("%d", &a[i]);
        tp[a[i]].push_back(i);
    }
    for (int i = 0, u, v; i<m; ++i) {
        scanf("%d%d", &u, &v);
        add(u, v); add(v, u);
    }
    for (int i = 1; i<=k; ++i) solve(i);
    for (int i = 1; i<=n; ++i) {
        sort(d[i]+1, d[i]+1+k);
        int cost = 0;
        for (int j = 1; j<=s; ++j) cost += d[i][j];
        printf(i==n ? "%d\n":"%d ", cost);
    }
    return 0;
}
posted @ 2020-08-04 22:10  shuitiangong  阅读(147)  评论(0编辑  收藏  举报