forked from kamyu104/LeetCode-Solutions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
count-subtrees-with-max-distance-between-cities.cpp
115 lines (109 loc) · 4.26 KB
/
count-subtrees-with-max-distance-between-cities.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Time: O(n^6)
// Space: O(n^3)
class Solution {
public:
vector<int> countSubgraphsForEachDiameter(int n, vector<vector<int>>& edges) {
vector<vector<int>> adj(n);
for (const auto& edge : edges) {
int u = edge[0] - 1, v = edge[1] - 1;
adj[u].emplace_back(v);
adj[v].emplace_back(u);
}
vector<int> lookup(n), result(n - 1);
for (int i = 0; i < n; ++i) { // Time: sum(O(k^5) for k in [1, n]) = O(n^6)
vector<vector<vector<int>>> dp(n, vector<vector<int>>(n, vector<int>(n)));
vector<int> count(n, 1);
dfs(n, adj, i, -1, lookup, &count, &dp); // Time: O(k^5), k is the number of the remaining cities
lookup[i] = 1;
for (int d = 1; d < n; ++d) { // for each depth from city i
for (int max_d = d; max_d < min(2 * d + 1, n); ++max_d) { // for each max distance
result[max_d - 1] += dp[i][d][max_d];
}
}
}
return result;
}
private:
void dfs(int n, const vector<vector<int>>& adj,
int curr, int parent,
const vector<int>& lookup,
vector<int> *count,
vector<vector<vector<int>>> *dp) {
for (const auto& child : adj[curr]) {
if (child == parent || lookup[child]) {
continue;
}
dfs(n, adj, child, curr, lookup, count, dp);
}
(*dp)[curr][0][0] = 1;
for (const auto& child : adj[curr]) {
if (child == parent || lookup[child]) {
continue;
}
vector<vector<int>> new_dp_curr = (*dp)[curr];
for (int curr_d = 0; curr_d < (*count)[curr]; ++curr_d) {
for (int curr_max_d = curr_d; curr_max_d < min(2 * curr_d + 1, (*count)[curr]); ++curr_max_d) {
if (!(*dp)[curr][curr_d][curr_max_d]) { // pruning
continue;
}
for (int child_d = 0; child_d < (*count)[child]; ++child_d) {
for (int child_max_d = child_d; child_max_d < min(2 * child_d + 1, (*count)[child]); ++child_max_d) {
new_dp_curr[max(curr_d, child_d + 1)][max({curr_max_d, child_max_d, curr_d + child_d + 1})] +=
(*dp)[curr][curr_d][curr_max_d] * (*dp)[child][child_d][child_max_d]; // count subtrees with new child
}
}
}
}
(*count)[curr] += (*count)[child]; // merge new child
(*dp)[curr] = move(new_dp_curr);
}
}
};
// Time: O(n * 2^n)
// Space: O(n)
class Solution2 {
public:
vector<int> countSubgraphsForEachDiameter(int n, vector<vector<int>>& edges) {
vector<vector<int>> adj(n);
for (const auto& edge : edges) {
int u = edge[0] - 1, v = edge[1] - 1;
adj[u].emplace_back(v);
adj[v].emplace_back(u);
}
vector<int> result(n - 1);
int total = 1 << n;
for (int mask = 1; mask < total; ++mask) {
int max_d = maxDistance(n, edges, adj, mask);
if (max_d - 1 >= 0) {
++result[max_d - 1];
}
}
return result;
}
private:
int maxDistance(int n,
const vector<vector<int>>& edges,
const vector<vector<int>>& adj,
int mask) {
const auto& [is_valid, farthest, max_d] = bfs(n, adj, mask, log(mask & -mask) / log(2));
return is_valid ? get<2>(bfs(n, adj, mask, farthest)) : 0;
}
tuple<bool, int, int> bfs(int n, const vector<vector<int>>& adj,
int mask, int start) {
queue<pair<int, int>> q({{start, 0}});
int lookup = (1 << start);
int count = __builtin_popcount(mask) - 1, u = -1, d = -1;
while (!empty(q)) {
tie(u, d) = move(q.front()); q.pop();
for (const auto& v : adj[u]) {
if (!(mask & (1 << v)) || (lookup & (1 << v))) {
continue;
}
lookup |= (1 << v);
--count;
q.emplace(v, d + 1);
}
}
return {count == 0, u, d};
}
};