掌握不了 自頂向下的智慧,差點放棄寫這題 ...
Part 1
今天題目有點複雜,我向往常一樣從開始試著直接寫到結束,結果頻頻碰壁,寫了一小時硬是一點能跑得程式碼都沒有,只剩下腦中凌亂的想法和螢幕上雜亂的註解與義大利麵。
沈澱一下後,我決定不管任何資料結構、不管任何實作。假裝我想要的全部都有,直接把整個都寫出來。
#include <algorithm>
#include <cmath>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#define EDGE_CALC(path, x, y, z) \
path = std::sqrt(std::pow(x, 2) +\
std::pow(y, 2) +\
std::pow(z, 2))\
typedef struct {
int x;
int y;
int z;
} Point;
int main() {
std::ifstream inputFile("input-day8");
std::string line;
// Store all points from inputFile
std::vector<Point> points;
while (std::getline(inputFile, line)) {
std::stringstream ss(line);
int x, y, z;
ss >> x >> y >> z;
points.push_back({x, y, z});
}
// Calculate edge basted on point1 and point2
float edge;
vector<> edges;
for (int i = 0; i < points.size(); i++) {
for (int j = i+1; j < points.size(); j++) {
float dx = points[i].x - points[j].x;
float dy = points[i].y - points[j].y;
float dz = points[i].z - points[j].z;
EDGE_CALC(edge, dx, dy, dz);
edges.push_back({edge, points[i], points[j]});
}
}
// Sort edges (std::less) (edge, point1, point2)
std::sort(edges.begin(), edges.end(), [](const auto& a, const auto& b){
return a.edge < b.edge;
});
// Init Disjoint Set
DS sets;
// Combine point1 and point2 in same disjoint set
for (auto edge : edges) {
Point point1 = edge.point1;
Point point2 = edge.point2;
sets[point1].combine(point2);
}
// Find the 3 largest Disjoint Set
vector<int> groupSize;
// Fill the groupSize
for (int i = 0; i < points.size(); i++) {
int root = sets.find(i);
if (root is not recorded yet)
groupSize.push_back(sets.getSize(root));
}
std::sort(groupSize.begin(), groupSize.end(), [](const auto& a, const auto& b){
return a.size < b.size;
});
long long result = sets[0].size * sets[1].size * sets[2].size;
std::cout << result;
}我寫出來大概長這麼一陀,但思路看註解應該就蠻清楚的了。但還欠缺很多,最主要就是資料型別的定義。
Edges 要如何定義?DS 又要怎麼搞?還沒做,其實也都是小事啦,但我現在感覺超爽,跟剛剛無頭蒼蠅的感覺真的完全不一樣了。
DS 就是 Disjoint Set,印象最深刻的就是它超級厲害的 find,時間複雜度是阿克曼函數。
總之寫出來長這樣
#include <algorithm>
#include <cmath>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#define EDGE_CALC(path, x, y, z) \
path = std::sqrt(std::pow(x, 2) +\
std::pow(y, 2) +\
std::pow(z, 2))\
typedef struct {
int x;
int y;
int z;
} Point;
typedef struct {
float weight;
int u; // Index
int v;
} Edge;
class DS {
public:
std::vector<int> parent;
std::vector<int> size;
DS(int n) {
parent.resize(n);
size.resize(n, 1);
for (int i = 0; i < n; i++) parent[i] = i;
}
int find(int i) {
if (parent[i] == i) return i;
return parent[i] = find(parent[i]);
}
void combine(int i, int j) {
int root_i = find(i);
int root_j = find(j);
if (root_i != root_j) {
parent[root_i] = root_j;
size[root_j] += size[root_i];
}
}
int getSize(int i) {
return size[find(i)];
}
};
int main() {
std::ifstream inputFile("input-day8");
std::string line;
// Store all points from inputFile
std::vector<Point> points;
while (std::getline(inputFile, line)) {
std::stringstream ss(line);
int x, y, z;
char junk;
ss >> x >> junk >> y >> junk >> z;
points.push_back({x, y, z});
}
// Calculate edge basted on point1 and point2
float edge;
std::vector<Edge> edges;
for (int i = 0; i < points.size(); i++) {
for (int j = i+1; j < points.size(); j++) {
float dx = points[i].x - points[j].x;
float dy = points[i].y - points[j].y;
float dz = points[i].z - points[j].z;
EDGE_CALC(edge, dx, dy, dz);
edges.push_back({edge, i, j});
}
}
// Sort edges (std::less) (edge, point1, point2)
std::sort(edges.begin(), edges.end(), [](const auto& a, const auto& b){
return a.weight < b.weight;
});
int limit = 1000;
if (edges.size() < limit) limit = edges.size();
// Init Disjoint Set
DS sets(points.size());
// Combine point1 and point2 in same disjoint set
for (int i = 0; i < limit; i++) {
sets.combine(edges[i].u, edges[i].v);
}
// Find the 3 largest Disjoint Set
std::vector<int> groupSize;
std::vector<bool> filled(points.size(), false);
// Fill the groupSize
for (int i = 0; i < points.size(); i++) {
int root = sets.find(i);
if (!filled[root]) {
filled[root] = true;
groupSize.push_back(sets.getSize(root));
}
}
std::sort(groupSize.begin(), groupSize.end(), [](const auto& a, const auto& b){
return a > b;
});
long long result = groupSize[0] * groupSize[1] * groupSize[2];
std::cout << result;
}Part 2
就稍微改一下就好。最後 root 不相等的 combine 就是最後兩個併查集連起來的 combine。就是這樣。
/*
...
*/
bool combine(int i, int j) {
int root_i = find(i);
int root_j = find(j);
if (root_i != root_j) {
parent[root_i] = root_j;
size[root_j] += size[root_i];
return true;
}
return false;
}
/*
...
*/
// Init Disjoint Set
long long result;
DS sets(points.size());
// Combine point1 and point2 in same disjoint set
for (int i = 0; i < edges.size(); i++) {
if (sets.combine(edges[i].u, edges[i].v))
result = (long long)points[edges[i].u].x * points[edges[i].v].x;
}
std::cout << result;
}明明 Leetcode 都刷了 500 題了,居然還會卡在這種題目這麼久 …。看來真的是 Hard 刷太少了吧。不知道接下來幾天還會有怎樣的題目呢。