Farmer John's farm consists of a set of?NN?fields?(1≤N≤105)(1≤N≤105), conveniently numbered?1…N1…N. Between these fields are?MM?bi-directed paths?(0≤M≤105)(0≤M≤105), each connecting a pair of fields.
The farm contains two barns, one in field 1 and the other in field?NN. Farmer John would like to ensure that there is a way to walk between the two barns along some series of paths. He is willing to build up to two new paths to accomplish this goal. Due to the way the fields are situated, the cost of building a new path between fields?ii?and?jj?is?(i?j)2(i?j)2.
Please help Farmer John determine the minimum cost needed such that barns?11?and?NN?become reachable from each-other.
Each input test case contains?TT?sub-cases (1≤T≤201≤T≤20), all of which must be solved correctly to solve the input case.The first line of input contains?TT, after which?TT?sub-test cases follow.
Each sub-test case starts with two integers,?NN?and?MM. Next,?MM?lines follow, each one containing two integers?ii?and?jj, indicating a path between two different fields?ii?and?jj. It is guaranteed that there is at most one path between any two fields, and that the sum of?N+MN+M?over all sub-test cases is at most?5?1055?105.
Output?TT?lines. The?iith line should contain a single integer giving the minimum cost for the?iith sub-test case.
2 5 2 1 2 4 5 5 3 1 2 2 3 4 5
2 1
In the first sub-test case, it is optimal to connect fields 2 and 3 with a path, and fields 3 and 4 with a path.
In the second sub-test case, it is optimal to connect fields 3 and 4 with a path. No second path is needed.
Problem credits: Nick Wu
[/hide]
(Analysis by Nick Wu)
To solve the first subtask, we can brute force all possible pairs of edges to add. This solution has complexity?O(N4(N+M))O(N4(N+M)).
To solve the second subtask, we need to be more disciplined in what edges we consider adding. We can start by computing the connected components of the barns - that is, maximal collections of barns where one can reach any barn from any other barn in the collection.
There are therefore two cases to consider here. We can either add an edge from the connected component containing barn 1 to the connected component containing barn?NN, or we pick an intermediate connected component, add one edge from it to the connected component containing barn?11, and add another edge from it to the connected component containing barn?NN.
This observation on its own only reduces the number of pairs of edges to consider in the worst case by a constant factor. However, we now have two independent instances of the same subproblem to solve - given two connected components, what is the minimum cost needed to connect them with a single edge?
We can naively brute force this for all pairs of components we care about, for an?O(N2)O(N2)?algorithm.
#include <algorithm> #include <iostream> #include <numeric> #include <vector> using namespace std; void dfs(const vector<vector<int>>& edges, vector<int>& component, const int currv, const int id) { for(int child: edges[currv]) { if(component[child] != id) { component[child] = id; dfs(edges, component, child, id); } } } void solve() { int n, m; cin >> n >> m; vector<vector<int>> edges(n); for(int i = 0; i < m; i++) { int a, b; cin >> a >> b; a--; b--; edges[a].push_back(b); edges[b].push_back(a); } vector<int> component(n); iota(component.begin(), component.end(), 0); for(int i = 0; i < n; i++) { if(component[i] == i) { dfs(edges, component, i, i); } } if(component[0] == component[n-1]) { cout << "0\n"; return; } vector<vector<int>> componentToVertices(n); for(int i = 0; i < n; i++) { componentToVertices[component[i]].push_back(i); } long long ans = 1e18; vector<long long> srccost(n, 1e9); vector<long long> dstcost(n, 1e9); for(int i: componentToVertices[component[0]]) { for(int j = 0; j < n; j++) { srccost[component[j]] = min(srccost[component[j]], (long long)abs(i - j)); } } for(int i: componentToVertices[component[n-1]]) { for(int j = 0; j < n; j++) { dstcost[component[j]] = min(dstcost[component[j]], (long long)abs(i - j)); } } for(int i = 0; i < n; i++) ans = min(ans, srccost[i]*srccost[i] + dstcost[i]*dstcost[i]); cout << ans << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int t; cin >> t; for(int i = 0; i < t; i++) { solve(); } return 0; }
To optimize this to?O(M+N)O(M+N)?time, we have to take advantage of the cost function.
For a given barn and a given connected component we want to connect it to, we only care about the smallest integer in the connected component greater than it, as well as the largest integer in the component less than it.
There are a couple ways to find these integers. One way would be to use binary search. It is also possible to do this in linear time by maintaining the pair of indices we consider and considering adding edges from vertex?ii?in increasing order of?ii. The pair of indices we consider will be nondecreasing, so we only consider a linear number of edges.
#include <algorithm> #include <iostream> #include <numeric> #include <vector> using namespace std; void dfs(const vector<vector<int>>& edges, vector<int>& component, const int currv, const int id) { for(int child: edges[currv]) { if(component[child] != id) { component[child] = id; dfs(edges, component, child, id); } } } void solve() { int n, m; cin >> n >> m; vector<vector<int>> edges(n); for(int i = 0; i < m; i++) { int a, b; cin >> a >> b; a--; b--; edges[a].push_back(b); edges[b].push_back(a); } vector<int> component(n); iota(component.begin(), component.end(), 0); for(int i = 0; i < n; i++) { if(component[i] == i) { dfs(edges, component, i, i); } } if(component[0] == component[n-1]) { cout << "0\n"; return; } vector<vector<int>> componentToVertices(n); for(int i = 0; i < n; i++) { componentToVertices[component[i]].push_back(i); } long long ans = 1e18; vector<long long> srccost(n, 1e9); vector<long long> dstcost(n, 1e9); int srcidx = 0; int dstidx = 0; for(int i = 0; i < n; i++) { while(srcidx < componentToVertices[component[0]].size()) { srccost[component[i]] = min(srccost[component[i]], (long long)abs(i - componentToVertices[component[0]][srcidx])); if(componentToVertices[component[0]][srcidx] < i) srcidx++; else break; } if(srcidx) srcidx--; while(dstidx < componentToVertices[component[n-1]].size()) { dstcost[component[i]] = min(dstcost[component[i]], (long long)abs(i - componentToVertices[component[n-1]][dstidx])); if(componentToVertices[component[n-1]][dstidx] < i) dstidx++; else break; } if(dstidx) dstidx--; } for(int i = 0; i < n; i++) ans = min(ans, srccost[i]*srccost[i] + dstcost[i]*dstcost[i]); cout << ans << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int t; cin >> t; for(int i = 0; i < t; i++) { solve(); } return 0; }
[/hide]
? 2025. All Rights Reserved. 沪ICP备2023009024号-1