📜  两球可达性游戏(1)

📅  最后修改于: 2023-12-03 15:35:57.138000             🧑  作者: Mango

两球可达性游戏

简介

两球可达性游戏(Two Balls Reachability Game,TBG)是一款基于图论的游戏,主要涉及到图的可达性问题。游戏通过给定一个有向图G,让玩家选择两个起点S1和S2,并通过一系列特定操作让S1和S2在图G中是否可达。

玩法
游戏规则
  1. 游戏开始时,给定一个有向图G,以及两个起点S1和S2。

  2. 玩家通过指定起点S1或S2,将起点标记在图G中。

  3. 玩家根据图G中的给定边和点的相关信息,选择添加或删除一条边或移动一个点,以达到让起点S1和S2在图G中可达的目的。

  4. 游戏结束条件:起点S1和S2在图G中可达。

游戏限制
  1. 有向图G中有n个节点,m条边,1 <= n, m <= 2000。

  2. 起点S1和S2是有向图G中的两个节点,1 <= S1, S2 <= n。

  3. 玩家每次操作只能添加或删除一条边,或者移动一个点。

  4. 玩家最多可以进行k次操作,1 <= k <= n。

游戏提示
  1. 可以使用广度优先搜索(BFS)或深度优先搜索(DFS)来判断起点S1和S2是否可达。

  2. 可以使用最小割树算法(Stoer-Wagner算法)来快速找到最小的连通块。

代码实现

一个简单的C++代码实现示例:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

const int MAXN = 2005;
const int INF = 0x3f3f3f3f;

struct Edge {
    int to, w;
};

vector<Edge> G[MAXN];
int dis[MAXN][2], vis[MAXN], tmp[MAXN];

inline void add_edge(int u, int v, int w) {
    G[u].push_back((Edge){v, w});
}

void bfs(int s, int t) {
    memset(vis, 0, sizeof(vis));
    memset(dis, INF, sizeof(dis));

    queue<pair<int, int>> q;
    dis[s][0] = dis[t][1] = 0;
    vis[s] = vis[t] = 1;
    q.push(make_pair(s, 0));
    q.push(make_pair(t, 1));

    while (!q.empty()) {
        int x = q.front().first, flag = q.front().second;
        q.pop();
        for (int i = 0; i < G[x].size(); i++) {
            Edge e = G[x][i];
            int to = e.to, w = e.w;
            if (dis[to][flag] > dis[x][flag] + w) {
                dis[to][flag] = dis[x][flag] + w;
                if (!vis[to]) {
                    vis[to] = 1;
                    q.push(make_pair(to, flag));
                }
            }
        }
    }
}

int find(int n) {
    int ans = INF;
    for (int k = 1; k <= n; k++) {
        int sum = 0, cnt = 0;
        memset(tmp, 0, sizeof(tmp));
        for (int i = 1; i <= n; i++) {
            if (!tmp[i]) {
                cnt++;
                int pre = 0;
                while (!tmp[i]) {
                    tmp[i] = 1;
                    pre = i;
                    i = (dis[i][0] < dis[i][1]) ? pre : i;
                }
                sum += (dis[pre][0] < dis[pre][1]) ? dis[pre][0] : dis[pre][1];
            }
        }
        ans = min(ans, sum);
    }
    return ans;
}

int main() {
    int n, m, k, s1, s2;
    scanf("%d%d%d%d%d", &n, &m, &k, &s1, &s2);
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add_edge(u, v, w);
    }

    bfs(s1, s2);
    int ans = find(n);

    if (ans > k) cout << "NO" << endl;
    else cout << "YES" << endl;

    return 0;
}
游戏示例

以以下图示为例,给出两个起点S1和S2,询问能否通过不超过3次的操作,让S1和S2在图G中达到可达状态。

图示

使用上面给出的代码实现,我们可以得到最终结果为YES,可以通过不超过3次的操作,让S1和S2在图G中达到可达状态。