Floyd

求无向图最小环问题

https://www.acwing.com/problem/content/346/

floyd是典型的插点算法,每次插入点k,为此,在点k被[插入前]可计算i-j-k这个环
即此时中间节点为:1~k-1,即我们已经算出了任意i<->j的最短道路,中间经过的节点可以为 (1,2,3,…,k-1)
我们只需枚举所有以k为环中最大节点的环即可。
pos[i][j]:i~j的最短路中经过的点是k(即由这个状态转移过来),且这个k是此路径中编号最大的点(除i,j)

const int N = 105;

int n, m;
int d[N][N], g[N][N];
int pos[N][N];
int path[N], cnt;

void get_path(int i, int j) {
    if (!pos[i][j]) return;

    int k = pos[i][j];
    get_path(i, k);
    path[cnt ++] = k;
    get_path(k, j);
}

int main() {
    cin >> n >> m;

    memset(g, 0x3f, sizeof g);
    while (m --) {
        int a, b, c; cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b], c);
    }

    int ans = INF;
    memcpy(d, g, sizeof d);
    for (int k = 1; k <= n; k ++) {
        // 枚举以k为最大编号的环
        for (int i = 1; i < k; i ++)
            for (int j = i + 1; j < k; j ++) 
                if ((LL)d[i][j] + g[i][k] + g[k][j] < ans) { // i->k->j->..->i
                    ans = d[i][j] + g[i][k] + g[k][j];

                    cnt = 0;
                    path[cnt ++] = k;
                    path[cnt ++] = i;
                    get_path(i, j);
                    path[cnt ++] = j;
                }

        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
                if (d[i][j] > d[i][k] + d[k][j]) {
                    d[i][j] = d[i][k] + d[k][j];
                    pos[i][j] = k;
                }
    }

    if (ans == INF) puts("No solution.");
    else {
        for (int i = 0; i < cnt; i ++) cout << path[i] << " \n"[i == cnt - 1];
    }
    return 0;
}

 

原文地址:http://www.cnblogs.com/Leocsse/p/16870968.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性