牛客2018多校一 Two Graphs (图 同构)

博客围绕牛客网题目展开,题目给出n个点,m1条边构成图1,m2条边构成图2,要求计算图1有多少子图与图2同构。题解指出先明确同构定义,即两图邻接矩阵相同,然后枚举图1所有子图,通过n个点全排列,判断边数并hash判重。

https://ac.nowcoder.com/acm/problem/17136
题意: 给 出 n 个 点 , m 1 条 边 表 示 图 1 , m 2 条 边 表 示 图 2 , 问 图 1 有 多 少 子 图 与 图 2 同 构 给出n个点,m1条边表示图1,m2条边表示图2,问图1有多少子图与图2同构 nm11m2212

题解: 首 先 明 白 同 构 的 定 义 : 当 两 图 同 构 时 , 对 应 点 相 同 , 对 应 边 相 同 , 即 两 图 的 邻 接 矩 阵 相 同 。 首先明白同构的定义:当两图同构时,对应点相同,对应边相同,即两图的邻接矩阵相同。

那 么 我 们 可 以 枚 举 图 1 的 所 有 子 图 , 即 n 个 点 的 全 排 列 , 判 断 边 数 是 否 相 同 , 然 后 h a s h 判 重 那么我们可以枚举图1的所有子图,即n个点的全排列,判断边数是否相同,然后hash判重 1nhash

#include<bits/stdc++.h>
using namespace std;
int n,m1,m2;
int e[10];
pair<int,int>p[105];
int mp[10][10];
set<unsigned long long>st;
int main(){
    while(cin>>n>>m1>>m2){
        st.clear();
        memset(mp,0,sizeof mp);
        for(int i = 1; i <= n; i++)
            e[i] = i;
        for(int i = 1,u,v; i <= m1; i++){
            cin>>u>>v;
            mp[u][v] = mp[v][u] = 1;
        }
        for(int i = 1; i <= m2; i++){
            cin>>p[i].first>>p[i].second;
        }
        do{
            unsigned long long base = 131,ha = 0,i;
            int cnt = 0;
            for(i = 1; i <= m2; i++){
                int fi = p[i].first,se = p[i].second;
                if(mp[e[fi]][e[se]] == 1){
                    cnt++;
                    ha = ha*base+i;
                }
            }
            if(cnt == m1){
                st.insert(ha);
            }
        }while(next_permutation(e+1,e+n+1));
        cout<<st.size()<<endl;
    }
}
网在 2018 年举办的 ACM 暑期训练营是系列面向算法竞赛爱好者的在线编程赛事,旨在帮助参赛者提升算法能力、团队协作能力以及对复杂问题的解决能力。比赛通常以团队为单位参与,每场比赛包含若干道编程题目,涉及图论、数据结构、动态规划、字符串等个算法领域。 ### 比赛题目与题型分布 比赛题目通常由个高或企业出题,涵盖难度从简单到困难的题目,例如: - **数学与数论**:包括模运算、素数判定、数列处理等。 - **图论**:涉及最短路径(Dijkstra、Floyd)、最小生成树(Kruskal、Prim)、拓扑排序等。 - **动态规划**:包括线性DP、区间DP、树形DP等。 - **字符串处理**:KMP、AC自动机、后缀数组等。 - **数据结构**:线段树、并查集、平衡树等。 - **组合数学与计算几何**:排列组合、概率期望、凸包等。 例如,在第六场的 G 题中,涉及树的性质和图论的网络流问题,需要计算所有点对之间的最大流之和,这要求对树上路径性质有深入理解[^1]。 ### 题解与解题思路 每场比赛结束后,网通常会发布官方题解,并鼓励选手在论坛或博中分享解题思路和代码。例如: - 在第四场的 G 题中,题目要求找出删除若干元素后使得众数唯的问题。题解中提出从大到小枚举可能的众数候选,并判断是否可以通过删除不超过 M 个元素来实现目标。此题需要注意内存初始化的问题,因为 T 的范围未知,常规的 `memset` 可能导致超时,因此建议使用 `map` 或其他结构进行优化[^4]。 - 在第场的 J 题中,使用了将数组扩展为两倍长度的技巧,以便处理环形数组问题,这种技巧在处理循环数组时非常常见且有效[^3]。 ### 比赛经验分享 参赛者通常会从以下几个方面总结经验: - **时间管理**:比赛通常为 3-5 小时,合理分配时间解出尽可能的题目是关键。 - **团队协作**:三人组队时,分工明确(如人主写代码,人读题,人调试)能显著提高效率。 - **模板积累**:熟练掌握常用算法模板(如快速幂、Dijkstra、线段树等)可大幅节省编码时间。 - **调试技巧**:使用断点调试、对拍工具等能快速发现代码中的错误。 - **赛后复盘**:分析未通过的题目,理解官方题解并尝试重新实现是提升的关键。 ### 示例代码 以下是个用于处理二维字符矩阵对称性的代码片段,来自第四场 D 题的解法: ```cpp #include <bits/stdc++.h> using namespace std; const int maxN = 2000 + 5; int n, m; char str[maxN][maxN]; int main() { int T; scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%s", str[i] + 1); int tp = -1; for (int i = 1; i <= n / 2; i++) { bool f = true; for (int j = 1; j <= m; j++) if (str[i][j] != str[n - i + 1][j]) { f = false; break; } if (!f) { tp = i; break; } } if (tp == -1) tp = n / 2; int tq = -1; for (int j = 1; j <= m / 2; j++) { bool f = true; for (int i = 1; i <= n; i++) if (str[i][j] != str[i][m - j + 1]) { f = false; break; } if (!f) { tq = j; break; } } if (tq == -1) tq = m / 2; int ans; if (tp == 1 || tq == 1) { ans = 0; } else { ans = (tp - 1) * (tq - 1); } printf("%d\n", ans); } return 0; } ``` 该代码通过逐行逐列判断矩阵的对称性,最终计算出可以保留的对称区域数量。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值