/* * Sample solution for Kingdom, NCPC 2005 * Author: Nils Grimsmo * * Algorithm: * - For max distance from each city to each town. * Dijkstra with neighbour matrix. O(V^2). * - For each road, find the placement on the road giving the minimum distance * to both cities. O(E). * - Binary search for the shortest distance to both cities, where placing * soldiers at maximally this distance, makes it possible to block the paths * between the cities. * - Find the maximum flow between the cities, where the capacity between * two towns/cities is 1 if the distance to both cities is below the * limit, "a lot" otherwise. Use push-relabel, O(V^3). * - If the maximum flow is above the number of soldiers available, the * roads cannot be blocked. * * Running time: * O(V^3 log(MaxPhi * V)) */ #include #include #include #include using namespace std; #ifndef _WIN32 using namespace __gnu_cxx; #endif int PINF = 1000000000; int NINF = -1000000000; #define MIN(A,B) ((A)<(B)?(A):(B)) #define MAX(A,B) ((A)>(B)?(A):(B)) #define ABS(A) ((A)>0?(A):(-(A))) //#define PRINTTIME typedef pair pint; #ifdef PRINTTIME #include #include #include double gettime() { struct timeval time; gettimeofday(&time, NULL); return time.tv_sec + ((double)time.tv_usec) / 1000000.0; } #endif class Kingdom { public: int nodes; int soldiers; int city1; int city2; int** distance; // distance between towns/cities vector* distlist; vector* neigh; int* cdist1; int* cdist2; int** roaddist; // distance from road between two towns to the furthest city int** capacity; Kingdom(int N, int M, int E) { //cerr << (double)E / (N * N) << endl; nodes = N + 2; soldiers = M; city1 = N; city2 = N + 1; distance = new int*[nodes]; distlist = new vector[nodes]; neigh = new vector[nodes]; roaddist = new int*[nodes]; capacity = new int*[nodes]; for (int i = 0; i < nodes; i++) { distance[i] = new int[nodes]; for (int j = 0; j < nodes; j++) { distance[i][j] = PINF; } roaddist[i] = new int[nodes]; capacity[i] = new int[nodes]; } cdist1 = new int[nodes]; cdist2 = new int[nodes]; for (int i = 0; i < E; i++) { int A, B, Phi; scanf("%d %d %d", &A, &B, &Phi); //cerr << "case " << A << " " << B << " " << Phi << "\n"; if (A == 95050) A = city1; if (B == 95050) B = city1; if (A == 104729) A = city2; if (B == 104729) B = city2; distance[A][B] = 2 * Phi; distance[B][A] = 2 * Phi; } for (int i = 0; i < nodes; i++) { for (int j = 0; j < nodes; j++) { if (distance[i][j] < PINF) { distlist[i].push_back(pint(j, distance[i][j])); neigh[i].push_back(j); } } } solve(); } ~Kingdom() { for (int i = 0; i < nodes; i++) { delete[] distance[i]; delete[] roaddist[i]; delete[] capacity[i]; } delete[] distance; delete[] distlist; delete[] neigh; delete[] roaddist; delete[] capacity; delete[] cdist1; delete[] cdist2; } void solve() { #ifdef PRINTTIME double t = gettime(); #endif findcitydist(); #ifdef PRINTTIME cerr << "findcitydist() " << gettime() - t << endl; t = gettime(); #endif findroaddist(); #ifdef PRINTTIME cerr << "findroaddist() " << gettime() - t << endl; t = gettime(); #endif int maxdist = 0; for (int u = 0; u < nodes; u++) { for (vector::iterator it = neigh[u].begin(); it != neigh[u].end(); it++) { if (roaddist[u][*it] < PINF) { maxdist = MAX(maxdist, roaddist[u][*it]); } } } int distlimit = maxdist + 2; int runs = 0; int low = 0; int high = distlimit; while (low < high) { int middle = (low + high) / 2; //middle = low; // linear search int mf = maxflow_ek(middle, distlimit); runs++; if (mf > soldiers) { low = middle + 1; } else { high = middle; } } if (low == distlimit) { printf("Impossible\n"); } else { printf("%.1lf\n", low / 2.0 + 1E-12); } #ifdef PRINTTIME cerr << "binary search " << gettime() - t << " "; cerr << " on " << runs << " runs\n\n"; #endif } void findcitydist() { one2all(city1, cdist1); one2all(city2, cdist2); } // dijkstra, O(V^2) void one2all(int city, int* cdist) { bool* done = new bool[nodes]; for (int i = 0; i < nodes; i++) { done[i] = false; cdist[i] = PINF; } cdist[city] = 0; int nextbest = city; for (int i = 0; i < nodes; i++) { int minval = PINF; int best = nextbest; done[best] = true; for (int j = 0; j < nodes; j++) { if (!done[j]) { if (cdist[best] + distance[best][j] < cdist[j]) { cdist[j] = cdist[best] + distance[best][j]; } if (cdist[j] < minval) { nextbest = j; minval = cdist[j]; } } } } delete[] done; } void findroaddist() { for (int i = 0; i < nodes; i++) { for (vector::iterator it = distlist[i].begin(); it != distlist[i].end(); it++) { int j = it->first; int dij = it->second; int c1i = cdist1[i]; int c2i = cdist2[i]; int c1j = cdist1[j]; int c2j = cdist2[j]; int min = PINF; // go to both cities from town i min = MIN(min, MAX(c1i, c2i)); // or town j min = MIN(min, MAX(c1j, c2j)); // city 1 for town i and city 2 from town j if (c1i < c1j && c2i > c2j) { min = MIN(min, MAX(MAX((c1i + dij + c2j) / 2, c1i), c2j)); } // city 2 for town i and city 1 from town j if (c1i > c1j && c2i < c2j) { min = MIN(min, MAX(MAX((c2i + dij + c1j) / 2, c2i), c1j)); } roaddist[i][j] = MIN(min, PINF); } } } int maxflow_pr(int maxdist, int distlimit) { int source = city1; int sink = city2; int* current = new int[nodes]; int* excess = new int[nodes]; int* height = new int[nodes]; for (int u = 0; u < nodes; u++) { current[u] = 0; height[u] = 0; excess[u] = 0; memset(capacity[u], 0, sizeof(int) * nodes); for (vector::iterator it = distlist[u].begin(); it != distlist[u].end(); it++) { int v = it->first; if (roaddist[u][v] > maxdist) { capacity[u][v] = distlimit; } else { capacity[u][v] = 1; } } } height[source] = nodes; for (vector::iterator it = neigh[source].begin(); it != neigh[source].end(); it++) { int v = *it; int send = capacity[source][v]; if (send > 0) { excess[source] -= send; excess[v] += send; capacity[source][v] -= send; capacity[v][source] += send; } } list que; for (int u = 0; u < nodes; u++) { if (u != source && u != sink) { que.push_back(u); } } list::iterator qit = que.begin(); while (qit != que.end()) { int u = *qit; int old_height = height[u]; // discharge(u); while (excess[u] > 0) { if (current[u] >= (int)neigh[u].size()) { // relabel(u); int min_height = height[u]; for (vector::iterator nit = neigh[u].begin(); nit != neigh[u].end(); nit++) { int v = *nit; if (capacity[u][v] > 0) { min_height = MIN(min_height, height[v]); } } height[u] = min_height + 1; current[u] = 0; } else { int v = neigh[u][current[u]]; if (capacity[u][v] > 0 && height[u] > height[v]) { // push(u, v); int send = MIN(excess[u], capacity[u][v]); excess[u] -= send; excess[v] += send; capacity[u][v] -= send; capacity[v][u] += send; } else { current[u]++; } } } if (height[u] > old_height) { que.erase(qit); que.push_front(u); qit = que.begin(); } qit++; } int mf = excess[sink]; delete[] current; delete[] excess; delete[] height; return mf; } int maxflow_ek(int maxdist, int distlimit) { for (int u = 0; u < nodes; u++) { memset(capacity[u], 0, sizeof(int) * nodes); for (vector::iterator it = distlist[u].begin(); it != distlist[u].end(); it++) { int v = it->first; if (roaddist[u][v] > maxdist) { capacity[u][v] = distlimit; } else { capacity[u][v] = 1; } } } int totalflow = 0; while (true) { int flow = augment(city1, city2); if (flow == 0) { break; } totalflow += flow; } return totalflow; } int augment(int source, int sink) { vector parent(nodes, 0); vector found(nodes, false); queue que; que.push(source); while (que.size()) { int u = que.front(); que.pop(); for (vector::iterator it = neigh[u].begin(); it != neigh[u].end(); it++) { int v = *it; if (! found[v] && capacity[u][v] > 0) { found[v] = true; parent[v] = u; if (v == sink) { int mincap = PINF; int w = v; while (w != source) { mincap = MIN(mincap, capacity[parent[w]][w]); w = parent[w]; } w = v; while (w != source) { capacity[parent[w]][w] -= mincap; capacity[w][parent[w]] += mincap; w = parent[w]; } return mincap; } que.push(v); } } } return 0; } }; int main() { while (true) { int N, M, E; cin >> N >> M >> E; if (!cin) { return 0; } Kingdom k(N, M, E); } }