【算法分析】——优化visit数组的重置操作

151 阅读3分钟

有时候,需要以数据中的每一项为起点进行dfs或者bfs,比如寻找二分图的最大匹配问题,此时一般要借助visit数组来标记某一项是否被访问过了,避免死循环。在数据量较大的情况下,visit数组开得也比较大,多次memset整个visit数组要花很长时间。

二分图

二分图:简单来说,如果图中点可以被分为两组,并且使得所有边都跨越组的边界,则这就是一个二分图。准确地说:把一个图的顶点划分为两个不相交集 U 和V ,使得每一条边都分别连接U、V中的顶点。如果存在这样的划分,则此图为一个二分图。二分图的一个等价定义是:不含有「含奇数条边的环」的图。图 1 是一个二分图。为了清晰,我们以后都把它画成图 2 的形式。

匹配

匹配:在图论中,一个 「匹配」(matching) 是一个边的集合,其中任意两条边都没有公共顶点。例如,图 3、图 4 中红色的边就是图 2 的匹配。

我们定义匹配点匹配边未匹配点非匹配边,它们的含义非常显然。例如图 3 中 1、4、5、7 为匹配点,其他顶点为未匹配点;1-5、4-7为匹配边,其他边为非匹配边。

最大匹配

最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。图 4 是一个最大匹配,它包含 4 条匹配边。

如下图所示,如果在某一对男孩和女孩之间存在相连的边,就意味着他们彼此喜欢。是否可能让所有男孩和女孩两两配对,使得每对儿都互相喜欢呢?图论中,这就是完美匹配问题。如果换一个说法:最多有多少互相喜欢的男孩/女孩可以配对儿?这就是最大匹配问题

想法分析

以下代码展示了一般的做法:

# include <bits/stdc++.h>
using namespace std;
int n, mx, a[100005], vis[100005];
void bfs(int x) {
    queue<int> q;
    q.push(x); vis[x] = 1;
    while (!q.empty()) {
        int t = q.front(); q.pop();
        cout << t << " ";
        if (2*t <= mx && !vis[2*t])
            q.push(2*t), vis[2*t] = 1;
        if (t/2 >= 1  && !vis[t/2])
            q.push(t/2), vis[t/2] = 1;
    }
    cout << endl;
}
int main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        mx = max(mx, a[i]);
    }
    for (int i = 0; i < n; i++) {
        memset(vis, 0, sizeof(vis));
        bfs(a[i]);
    }
    return 0;
}

其实没有必要每次都调用memset重置vis数组,考虑用id作为搜索时是否访问过的标记,代码如下:

# include <bits/stdc++.h>
using namespace std;
int n, mx, a[100005], vis[100005];
void bfs(int c, int x) {
    queue<int> q;
    q.push(x); vis[x] = c;
    while (!q.empty()) {
        int t = q.front(); q.pop();
        cout << t << " ";
        if (2*t <= mx && vis[2*t] != c)
            q.push(2*t), vis[2*t] = c;
        if (t/2 >= 1  && vis[t/2] != c)
            q.push(t/2), vis[t/2] = c;
    }
    cout << endl;
}
int main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        mx = max(mx, a[i]);
    }
    for (int i = 0; i < n; i++)
        bfs(i+1, a[i]);
    return 0;
}

资源传送门

  • 关注【做一个柔情的程序猿】公众号
  • 在【做一个柔情的程序猿】公众号后台回复 【python资料】【2020秋招】 即可获取相应的惊喜哦!
  • 自己搭建的博客地址梦魇回生的博客 在

「❤️ 感谢大家」

  • 点赞支持下吧,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)
  • 欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程