/* * 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 Ford-Fulkerson, O(E^2 V). * - If the maximum flow is above the number of soldiers available, the * roads cannot be blocked. * * Running time: * O(E^2 V log(MaxPhi * V)) */ #include #include #include #include using namespace std; 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 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]; roaddist = new int*[nodes]; capacity = new int*[nodes]; for (int i = 0; i < nodes; i++) { distance[i] = new int[nodes]; roaddist[i] = new int[nodes]; capacity[i] = new int[nodes]; for (int j = 0; j < nodes; j++) { distance[i][j] = PINF; } } 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; } solve(); } ~Kingdom() { for (int i = 0; i < nodes; i++) { delete[] distance[i]; delete[] roaddist[i]; delete[] capacity[i]; } delete[] distance; 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 (int v = 0; v < nodes; v++) { if (roaddist[u][v] < PINF) { maxdist = MAX(maxdist, roaddist[u][v]); } } } 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 (int j = 0; j < nodes; j++) { int dij = distance[i][j]; if (dij < PINF) { 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); } else { roaddist[i][j] = PINF; } } } } int maxflow_ek(int maxdist, int distlimit) { for (int u = 0; u < nodes; u++) { for (int v = 0; v < nodes; v++) { if (distance[u][v] < PINF) { if (roaddist[u][v] > maxdist) { capacity[u][v] = distlimit; } else { capacity[u][v] = 1; } } else { capacity[u][v] = 0; } } } int totalflow = 0; while (true) { int flow = augment_bfs(city1, city2); if (flow == 0) { break; } totalflow += flow; } return totalflow; } int augment_bfs(int source, int sink) { vector parent(nodes, -1); vector found(nodes, false); queue que; que.push(source); while (que.size()) { int u = que.front(); que.pop(); for (int v = 0; v < nodes; v++) { 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 augment_dfs(int source, int sink) { vector parent(nodes, -1); vector found(nodes, false); deque stack; stack.push_back(source); while (stack.size()) { int u = stack.front(); stack.pop_front(); found[u] = true; for (int v = 0; v < nodes; v++) { if (! found[v] && capacity[u][v] > 0) { 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; } stack.push_back(v); } } } return 0; } int augment_dfsr(int source, int sink) { int* parent = new int[nodes]; bool* found = new bool[nodes]; for (int u = 0; u < nodes; u++) { parent[u] = -1; found[u] = false; } dfs_visit(source, found, parent, sink); int mincap = 0; if (found[sink]) { mincap = PINF; int w = sink; int plen = 0; while (w != source) { mincap = MIN(mincap, capacity[parent[w]][w]); w = parent[w]; } w = sink; while (w != source) { plen += 1; capacity[parent[w]][w] -= mincap; capacity[w][parent[w]] += mincap; w = parent[w]; } } delete[] parent; delete[] found; return mincap; } void dfs_visit(int u, bool* found, int* parent, int sink) { found[u] = true; if (found[sink]) { return; } for (int v = 0; v < nodes; v++) { if (!found[v] && capacity[u][v] > 0) { parent[v] = u; dfs_visit(v, found, parent, sink); } } } }; int main() { while (true) { int N, M, E; cin >> N >> M >> E; if (!cin) { return 0; } //cerr << "read " << N << " " << M << " " << E << endl; Kingdom k(N, M, E); } }