记录编号 598043 评测结果 AAAAAA
题目名称 原神一统计划 最终得分 100
用户昵称 Gravatar健康铀 是否通过 通过
代码语言 C++ 运行时间 0.518 s
提交时间 2024-12-26 21:00:36 内存使用 83.72 MiB
显示代码纯文本
#include<bits/stdc++.h>
using namespace std;

int n, m, vis[110][110], nm[110][110], cnt = 0, d[20][20], f[20][1 << 20], ans, u[20], dp[20][55][55];

// 深度优先搜索,标记每个岛屿
void dfs(int x, int y, int k) {
    if (nm[x][y] <= 0 || x < 1 || y < 1 || x > n || y > m || vis[x][y] == 1)
        return;
    nm[x][y] = k;
    vis[x][y] = 1;
    dfs(x + 1, y, k);
    dfs(x, y + 1, k);
    dfs(x - 1, y, k);
    dfs(x, y - 1, k);
}

// 计算岛屿间的最短游泳路径
void get(int x, int y, int k, int s) {
    if (nm[x][y] < 0 || x < 1 || y < 1 || x > n || y > m)
        return;
    if (dp[k][x][y] >= 0) {
        if (s >= dp[k][x][y])
            return;
    }
    dp[k][x][y] = s;
    if (nm[x][y] > 0 && nm[x][y] != k) {
        d[k][nm[x][y]] = min(d[k][nm[x][y]], s);
        if (u[nm[x][y]] == 0) {
            k = nm[x][y];
            dp[k][x][y] = 0;
            u[k] = 1;
            s = 0;
        }
        else
            return;
    }
    if (nm[x][y] == 0) {
        s++;
    }
    get(x + 1, y, k, s);
    get(x, y + 1, k, s);
    get(x - 1, y, k, s);
    get(x, y - 1, k, s);
}

int main() {
	freopen("nl.in","r",stdin);
	freopen("nl.out","w",stdout); 
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            char a;
            cin >> a;
            if (a == 'X') {
                nm[i][j] = 1;
            } else if (a == 'S') {
                nm[i][j] = 0;
            } else {
                nm[i][j] = -1;
            }
        }
    }

    // 标记岛屿
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (nm[i][j] > 0 && vis[i][j] == 0) {
                dfs(i, j, ++cnt);
            }
        }
    }

    memset(vis, 0, sizeof(vis));
    memset(d, 0x3f, sizeof(d));
    memset(dp, -1, sizeof(dp));

    // 计算岛屿间的最短游泳路径
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (nm[i][j] == 0 || nm[i][j] == -1)
                continue;
            if (u[nm[i][j]] == 0) {
                u[nm[i][j]] = 1;
                get(i, j, nm[i][j], 0);
            }
        }
    }

    // 使用 Floyd 算法计算最短路径
    for (int k = 1; k <= cnt; k++) {
        for (int i = 1; i <= cnt; i++) {
            for (int j = 1; j <= cnt; j++) {
                if (i != j)
                    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }

    memset(f, 0x3f, sizeof(f));
    ans = 0x3f3f3f3f;
    for (int i = 1; i <= cnt; i++) {
        f[i][1 << (i - 1)] = 0;
    }

    // 动态规划求解最短游泳路径
    for (int j = 0; j < (1 << cnt); j++) {
        for (int i = 1; i <= cnt; i++) {
            if ((j & (1 << (i - 1))) == 0 || f[i][j] > 1e8)
                continue;
            for (int k = 1; k <= cnt; k++) {
                if ((j & (1 << (k - 1))) != 0)
                    continue;
                f[k][j | (1 << (k - 1))] = min(f[k][j | (1 << (k - 1))], f[i][j] + d[i][k]);
            }
        }
    }

    for (int i = 1; i <= cnt; i++) {
        ans = min(ans, f[i][(1 << cnt) - 1]);
    }
    cout << ans;
    return 0;
}