ACM ICPC Live Archive 3902

ACM ICPC Live Archive 3902

Problem Statement

Wrong:

Take the root, S, and use Dijkstra's to try to find the shortest path between S and every other leaf. Once an optimal new server is found, repeat the process, but with both S and the new server. Keep adding new servers until the distance is less than or equal to K.

Notice that for one thing, this is immensely inefficient in terms of time. It is repeating repeating Dijkstra's. So no.
Furthermore, this will not create the most optimal node set. What if the range of one of these new servers overlap with the range of one of the old servers?
Lastly, this is complicated beyond need. The following method is simpler:

Analysis

The "network" is an acylic graph. However, by marking a node, S, on the graph, as a "propagation center", i.e. root, it effectively becomes an directed acylic graph, which can be reorganized into a tree.
Notice that the network is an acylic graph. Normally, acyclic graphs don't come by themselves, they often have a root and can be organized into trees.
After organization, it is much easier to do searches (in this case, DFS) on the network.

Two DFS have to be done.
The initial DFS tracks each leaf of the network (i.e. clients). This then stores them by height. Furthermore, this tracks each node's parent in the network.
The second DFS does "propogation" from a certain node that we need to add a server in, and sees how many nodes this covers.

To count how many nodes we need in total, count backwards from N-1 to K. We see how many leafs are of distance N-1 to S, take the first one,"rewind" using the stored parents, and put a server there. Then, do the second DFS to see how many nodes are "covered".
Repeat this until all nodes of distance N-1 is done. If a node is already "covered", skip it.
Repeat for all distances up to K.

Code

#include <iostream>
#include <vector>
#include <cstring>
#define MAXN 1005
using namespace std; 

int p[MAXN], N, S, K;
bool v[MAXN];
vector<int> elist[MAXN], leafs[MAXN];

void dfsA(int i, int f, int d)
{
    p[i] = f;
    if(elist[i].size() == 1 && d > K) leafs[d].push_back(i);
    for(int c:elist[i]) if(c != f) dfsA(c, i, d+1);
}

void dfsB(int i, int f, int d)
{
    if(d > K) return;
    v[i] = true;
    for(int c:elist[i]) if(c != f) dfsB(c, i, d+1);
}

int main()
{
    ios_base::sync_with_stdio(false); cin.tie(nullptr);
    int tcn; cin >> tcn;
    while(tcn--)
    {
        memset(p, 255, sizeof p); memset(v, 0, sizeof v);
        for(int i=0; i<MAXN; i++) { elist[i].clear(); leafs[i].clear(); }
        cin >> N >> S >> K;
        for(int i=0; i<N-1; i++)
        {
            int s, e; cin >> s >> e;
            elist[s].push_back(e);
            elist[e].push_back(s);
        }
        dfsA(S, -1, 0);
        int ans = 0;
        for(int d=N-1; d>K; d--)
            for(int i:leafs[d])
            {
                if(v[i]) continue;
                int f=i; for(int j=0; j<K; j++) f=p[f];
                dfsB(f, -1, 0);
                ans++;
            }
        cout << ans << endl;
    }
}


Comments

Popular posts from this blog

USACO Training "subset": Subset Sums

USACO 2018 Open: Talent Show

OpenJudge 1768: Kadane's Algorithm on 2D Arrays