20220228 1601. 最多可達成的換樓請求數目
題目鏈接:https://leetcode-cn.com/problems/maximum-number-of-achievable-transfer-requests/
方法一:DFS 枚舉
枚舉所有換樓請求的選擇與不選擇兩種情況,最後判斷是否滿足題意,時間複雜度爲 O(2 ^ m),m 爲請求個數,依題意 m <= 16,符合要求。
1 #include <cstring> 2 3 const int N = 25; 4 5 class Solution { 6 public: 7 int a[N][N], b[N]; 8 int dfs(int o, int x, int n, int m) { 9 int res = 0; 10 if (o == m) { 11 int tot = 0; 12 for (int i = 0; i < n; i++) { 13 for (int j = 0; j < m; j++) 14 tot += (b[j] ? a[j][i] : 0); 15 if (tot != 0) return 0; 16 } 17 return x; 18 } 19 b[o] = 1; 20 res = dfs(o + 1, x + 1, n, m); 21 b[o] = 0; 22 res = max(res, dfs(o + 1, x, n, m)); 23 return res; 24 } 25 int maximumRequests(int n, vector<vector<int>>& requests) { 26 int m = requests.size(); 27 for (int i = 0; i < m; i++) 28 a[i][requests[i][0]] += -1, a[i][requests[i][1]] += 1; 29 memset(b, 0, sizeof(b)); 30 return dfs(0, 0, n, m); 31 } 32 };
其實不用轉換爲二維數組,可以節省空間,並且 DFS 過程中就可以維護是否滿足條件而不需要最後用 for 循環判斷,代碼有優化空間。
方法二:二進制位運算枚舉
由於對於請求只有選擇與不選擇兩種可能,使用二進制位運算,會大幅精簡代碼,但需要再最後用 for 循環判斷是否滿足條件,故時間複雜度會達到 O(n * 2 ^ m)。
1 const int N = 25; 2 3 class Solution { 4 public: 5 int maximumRequests(int n, vector<vector<int>>& r) { 6 int a[N], m = r.size(), ans = 0; 7 for (int o = 0; o < (1 << m); o++) { 8 memset(a, 0, sizeof(a)); 9 int res = 0; 10 for (int i = 0; i < m; i++) 11 if (o & (1 << i)) 12 a[r[i][0]]--, a[r[i][1]]++, res++; 13 int tot = 0; 14 for (int i = 0; i < n; i++) 15 tot += (a[i] == 0); 16 if (tot == n) ans = max(res, ans); 17 } 18 return ans; 19 } 20 };
其他:最小費用最大流
由於數據量並不大,用網絡流有點殺雞用牛刀了。