AcWing 1250. 格子游戏

AcWing 1250. 格子游戏

鉴定为简单的并查集模板题, 下面介绍并查集以及该题思路

并查集是什么?

并查集是一种数据结构, 通过一棵树来存储一组有关联的数据, 以此题为例, 即是用一颗树来维护一段由边串连起来的连通块, 主要操作有查找祖先节点以及合并两个并查集, 会维护自己的父亲节点。

查找祖先节点\((find)\)

最朴素的做法便是沿着父亲节点向上爬到根节点。
暂无图片

int find(int x)
{
    if(x == fa[x])
    {
        return x;
    }
    return find(fa[x]);
}

但是这样的时间复杂度在一个有\(n\)个节点的并查集下操作, 时间复杂度最高可达\(O(n)\), 很明显, 这需要优化。
所以我们可以用一种名为路径压缩的办法, 用\(fa[]\)数组直接存储根节点, 在返回结果的同时更新\(fa[]\)数组即可。
暂无图片

int find(int x)
{
    if(x == fa[x])
    {
        return x;
    }
    return fa[x] = find(fa[x]);
}

合并两个并查集\((merge)\)

将一个节点\(x\)的根节点\(find(x)\)设为另一个节点\(y\)根节点\(find(y)\)的父亲节点, 特殊的, 若\(find(x) = find(y)\), 则说明两个节点在同一个并查集内, 无需合并。

 ![暂无图片](http://)
bool merge(int x, int y)
{
    int fx = find(x), fy = find(y);
    if(fx == fy)
    {
        return 0;
        //在同一个并查集内, 无需合并
    }
    fa[fx] = fy;
    return 1;
    //合并成功
}

本题思路

考虑将一段联通的点存入一个并查集, 建立一条边时, 将边的两个端点所在的并查集合并, 若两点已在同一个并查集内, 则说明出现环。
暂无图片

int main()
{
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            int pos = (i - 1) * n + j;
            fa[pos] = pos;
        }
    }
    for(int i = 1; i <= m; i++)
    {
        int x, y, p1, p2;
        char dir;
        cin >> x >> y >> dir;
        p1 = (x - 1) * n + y;
        if(dir == 'D')
        {
            p2 = p1 + n;
        }
        else
        {
            p2 = p1 + 1;
        }
        if(!merge(p1, p2))
        {
            cout << i << '\n';
            return 0;
        }
    }
    cout << "draw" << '\n';
    return 0;
}
posted @ 2025-11-25 13:31  ly_fish  阅读(2)  评论(0)    收藏  举报