diff --git a/A difficult math contest b/A difficult math contest new file mode 100644 index 0000000..14126b6 --- /dev/null +++ b/A difficult math contest @@ -0,0 +1,547 @@ +#include + +#include + +#include + +#include + +#include + +#include + +#include + +#include + +#include + +#include + +#include + +#include + +#include + + + +using namespace std; + + + +class Graph { + +public: + + int n, m, k; + + vector> adj; + + vector degree; + + + + Graph(int n, int m, int k) : n(n), m(m), k(k) { + + adj.resize(n); + + degree.resize(n, 0); + + } + + + + void addEdge(int u, int v) { + + adj[u].push_back(v); + + adj[v].push_back(u); + + degree[u]++; + + degree[v]++; + + } + + + + void sortAdjLists() { + + for (int i = 0; i < n; i++) { + + sort(adj[i].begin(), adj[i].end()); + + } + + } + +}; + + + +class SubgraphMiner { + +private: + + Graph& graph; + + unordered_map frequentSubgraphs; // 序列化子图 -> 支持度 + + + +public: + + SubgraphMiner(Graph& g) : graph(g) {} + + + + // 序列化顶点集为字符串键 + + string getKey(const vector& vertices) { + + string key; + + for (int v : vertices) { + + key += to_string(v) + ","; + + } + + return key; + + } + + + + // 检查子图是否连通(BFS) + + bool isConnected(const vector& vertices, const unordered_set& vertexSet) { + + if (vertices.empty()) return true; + + + + unordered_set visited; + + queue q; + + q.push(vertices[0]); + + visited.insert(vertices[0]); + + + + while (!q.empty()) { + + int u = q.front(); + + q.pop(); + + + + for (int v : graph.adj[u]) { + + if (vertexSet.find(v) != vertexSet.end() && visited.find(v) == visited.end()) { + + visited.insert(v); + + q.push(v); + + } + + } + + } + + + + return visited.size() == vertexSet.size(); + + } + + + + // 挖掘大小为1的子图 + + void mineSize1() { + + for (int i = 0; i < graph.n; i++) { + + if (graph.degree[i] >= graph.k - 1) { // 单个顶点的支持度至少为k + + frequentSubgraphs[getKey({i})] = graph.degree[i] + 1; // 包括自身 + + } + + } + + } + + + + // 挖掘大小为2的子图(边) + + void mineSize2() { + + for (int u = 0; u < graph.n; u++) { + + for (int v : graph.adj[u]) { + + if (u < v) { // 避免重复 + + int support = 0; + + // 计算共同邻居数量作为支持度的近似 + + vector commonNeighbors; + + set_intersection( + + graph.adj[u].begin(), graph.adj[u].end(), + + graph.adj[v].begin(), graph.adj[v].end(), + + back_inserter(commonNeighbors) + + ); + + support = commonNeighbors.size() + 2; // 包括u和v本身 + + + + if (support >= graph.k) { + + frequentSubgraphs[getKey({u, v})] = support; + + } + + } + + } + + } + + } + + + + // 扩展候选子图(基于最小度优先) + + vector> extendCandidate(const vector& candidate) { + + vector> extensions; + + unordered_set candidateSet(candidate.begin(), candidate.end()); + + + + // 找到当前候选子图中度最小的顶点 + + int minDegreeVertex = candidate[0]; + + for (int v : candidate) { + + if (graph.degree[v] < graph.degree[minDegreeVertex]) { + + minDegreeVertex = v; + + } + + } + + + + // 从最小度顶点的邻居中寻找扩展 + + for (int neighbor : graph.adj[minDegreeVertex]) { + + if (candidateSet.find(neighbor) == candidateSet.end()) { + + vector newCandidate = candidate; + + newCandidate.push_back(neighbor); + + sort(newCandidate.begin(), newCandidate.end()); + + + + // 检查连通性 + + unordered_set newSet(newCandidate.begin(), newCandidate.end()); + + if (isConnected(newCandidate, newSet)) { + + extensions.push_back(newCandidate); + + } + + } + + } + + + + return extensions; + + } + + + + // 使用投影技术计算子图支持度 + + int calculateSupport(const vector& subgraph) { + + if (subgraph.size() <= 2) { + + return frequentSubgraphs[getKey(subgraph)]; + + } + + + + // 对于较大的子图,使用更精确的支持度计算 + + unordered_set subgraphSet(subgraph.begin(), subgraph.end()); + + int support = 0; + + + + // 简单的实现:计算包含所有顶点的公共邻居 + + // 实际应用中应该使用更复杂的投影数据库技术 + + vector> neighborSets; + + for (int v : subgraph) { + + neighborSets.emplace_back(graph.adj[v].begin(), graph.adj[v].end()); + + } + + + + // 找到共同邻居 + + unordered_set commonNeighbors = neighborSets[0]; + + for (size_t i = 1; i < neighborSets.size(); i++) { + + unordered_set temp; + + for (int n : commonNeighbors) { + + if (neighborSets[i].find(n) != neighborSets[i].end()) { + + temp.insert(n); + + } + + } + + commonNeighbors = move(temp); + + } + + + + support = commonNeighbors.size() + subgraph.size(); + + return max(0, support); + + } + + + + // 挖掘大小≥3的子图 + + void mineLargerSubgraphs() { + + queue> candidates; + + + + // 从大小为2的频繁子图开始 + + for (const auto& entry : frequentSubgraphs) { + + if (entry.first.find(',') != string::npos) { // 大小为2的子图 + + string key = entry.first; + + vector subgraph; + + size_t pos = 0; + + while ((pos = key.find(',')) != string::npos) { + + subgraph.push_back(stoi(key.substr(0, pos))); + + key.erase(0, pos + 1); + + } + + candidates.push(subgraph); + + } + + } + + + + while (!candidates.empty()) { + + vector candidate = candidates.front(); + + candidates.pop(); + + + + if (candidate.size() >= 4) continue; // 限制子图大小≤4 + + + + vector> extensions = extendCandidate(candidate); + + + + for (const auto& newCandidate : extensions) { + + string key = getKey(newCandidate); + + + + // 避免重复处理 + + if (frequentSubgraphs.find(key) != frequentSubgraphs.end()) { + + continue; + + } + + + + int support = calculateSupport(newCandidate); + + if (support >= graph.k) { + + frequentSubgraphs[key] = support; + + if (newCandidate.size() < 4) { // 继续扩展直到大小=4 + + candidates.push(newCandidate); + + } + + } + + } + + } + + } + + + + // 主挖掘函数 + + void mine() { + + cout << "Mining size 1 subgraphs..." << endl; + + mineSize1(); + + + + cout << "Mining size 2 subgraphs..." << endl; + + mineSize2(); + + + + cout << "Mining larger subgraphs..." << endl; + + mineLargerSubgraphs(); + + } + + + + // 输出结果 + + void printResults() { + + // 按子图大小和字典序排序 + + map> sortedResults; + + + + for (const auto& entry : frequentSubgraphs) { + + int size = count(entry.first.begin(), entry.first.end(), ',') + 1; + + sortedResults[size][entry.first] = entry.second; + + } + + + + for (const auto& sizeGroup : sortedResults) { + + for (const auto& entry : sizeGroup.second) { + + cout << "[" << entry.first.substr(0, entry.first.size() - 1) << "] " + + << entry.second << endl; + + } + + } + + } + +}; + + + +int main() { + + int n, m, k; + + cin >> n >> m >> k; + + + + Graph graph(n, m, k); + + + + for (int i = 0; i < m; i++) { + + int u, v; + + cin >> u >> v; + + graph.addEdge(u, v); + + } + + + + graph.sortAdjLists(); + + + + SubgraphMiner miner(graph); + + miner.mine(); + + miner.printResults(); + + + + return 0; + +}