无向图最小环

Link-Cut Tree (nowcoder.com)

题意:

无向图输出最小环上的边

思路:

可以按权值从小到大加边,直到出现环,之后dfs找环

实现:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <map>
#include <set>
#include <climits>
#include <unordered_map>
using namespace std;
#define mst(x, y) memset(x, y, sizeof x)
#define X first
#define Y second
#define int long long
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 200010, INF = 0x3f3f3f3f3f3f3f3f, MOD = 1e9 + 7;
const double EPS = 1e-6;
typedef pair<int, int> PII;
typedef unordered_map<int, int> Ump;
int T;
int n, m, a[N];
int p[N];
int u, v;
vector<PII> g[N];
int ans[N], top;
int find(int x) // 并查集
{
    if (p[x] != x)
        p[x] = find(p[x]);
    return p[x];
}
void dfs(int u, int fa)
{
    cout << u << ' ' << fa << endl;
    if (u == v)
    {
        sort(ans, ans + top);
        for (int i = 0; i < top; i++)
            cout << ans[i] << ' ';
        return;
    }
    for (auto t : g[u])
    {
        if (t.X == fa)
            continue;
        ans[top++] = t.Y;
        dfs(t.X, u);
        top--;
    }
}
void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        g[i].clear();
        p[i] = i;
    }

    bool f = false;
    for (int i = 1; i <= m; i++)
    {
        cin >> u >> v;
        if (f)
            continue;
        int pu = find(u), pv = find(v);
        if (pu != pv)
        {
            g[u].push_back({v, i});
            g[v].push_back({u, i});
            p[pu] = pv;
        }
        else
        {
            top = 0;
            f = true;
            dfs(u, -1);
            cout << i << endl;
        }
    }
    if (!f)
        cout << "-1" << endl;
}
signed main()
{
    FAST;
    cin >> T;
    // T = 1;
    while (T--)
        solve();
    return 0;
}

 

P6175 无向图的最小环问题 - 洛谷

 floyd求最小环

for (int k = 1; k <= n; k++)
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            g[i][j] = min(g[i][j], g[i][k] + g[k][j]);

说明:

第一层循环是枚举的所有中转点 k,然后枚举所有点对(i, j),以 k 为中转点看是否能够更新从 i 到 j 的最短距离。

所以说,当没有枚举到 k 时,g[i,j] 中存的是,从 i 到 j,经过所有编号小于 k 的所有节点的最短距离。节点 k 不在这个路径中。

所以,这时如果我们让节点 k 和节点 i 和节点 j 相连,那么就构成了一个至少为三个节点的环,环中没有重复节点。

这个环的权值就是:此时求得的从 i 到 j 的最短距离 + (i,k)的边权 + (k, j) 的边权,即 g[i,j] + w[i,k] + w[k,j]。枚举所有的点对 (i,j) 取所有这样的环的权值的最小值便是最小环的权值。

所以,我们就在枚举到中转点 k,并且在这个中转点更新其他点对的距离之前进行操作。

实现模板:

 

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <map>
#include <set>
#include <climits>
#include <unordered_map>
using namespace std;
#define mst(x, y) memset(x, y, sizeof x)
#define X first
#define Y second
#define int long long
#define FAST ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 200, INF = INT32_MAX, MOD = 1e9 + 7; // 这里INF初始化为更大的LLONG_MAX过不了不知道为什么
const double EPS = 1e-6;
typedef pair<int, int> PII;
typedef unordered_map<int, int> Ump;
int T;
int n, m;
int w[N][N];
int g[N][N];
int res = INF;
void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (i != j)
                g[i][j] = w[i][j] = INF;

    for (int i = 1; i <= m; i++)
    {
        int u, v, c;
        cin >> u >> v >> c;
        g[u][v] = g[v][u] = min(g[u][v], c);
        w[u][v] = w[v][u] = min(w[u][v], c);
    }

    for (int k = 1; k <= n; k++)
    {
        for (int i = 1; i < k; i++)
            for (int j = i + 1; j < k; j++)
                res = min(res, g[i][j] + w[i][k] + w[k][j]);

        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                g[i][j] = g[j][i] = min(g[i][j], g[i][k] + g[k][j]);
    }

    if (res == INF)
        cout << "No solution." << endl;
    else
        cout << res << endl;
    // cout << LLONG_MAX << endl;
}
signed main()
{
    FAST;
    // cin >> T;
    T = 1;
    while (T--)
        solve();
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Floyd算法找到无向图最小,可以先使用Floyd算法求出中任意两个顶点之间的最短路径,然后再遍历所有的三角形(三个顶点组成的)找到最小。 以下是一个使用Python实现Floyd算法求解无向图最小的示例: ```python INF = float('inf') def floyd(graph): n = len(graph) dist = [[INF] * n for _ in range(n)] # 初始化距离矩阵 next_vertex = [[-1] * n for _ in range(n)] # 记录最短路径上的下一个顶点 # 初始化距离矩阵和下一个顶点矩阵 for i in range(n): for j in range(n): if i == j: dist[i][j] = 0 elif graph[i][j] != 0: dist[i][j] = graph[i][j] next_vertex[i][j] = j # 使用Floyd算法计算最短路径和下一个顶点 for k in range(n): for i in range(n): for j in range(n): if dist[i][j] > dist[i][k] + dist[k][j]: dist[i][j] = dist[i][k] + dist[k][j] next_vertex[i][j] = next_vertex[i][k] return dist, next_vertex def find_min_cycle(graph): n = len(graph) min_cycle_length = INF dist, next_vertex = floyd(graph) # 遍历所有三角形,找到最小 for u in range(n): for v in range(u+1, n): for w in range(v+1, n): if graph[u][v] != 0 and graph[v][w] != 0 and graph[w][u] != 0: cycle_length = dist[u][v] + dist[v][w] + dist[w][u] - 2 * (graph[u][v] + graph[v][w] + graph[w][u]) if cycle_length < min_cycle_length: min_cycle_length = cycle_length return min_cycle_length ``` 使用上述代码,可以通过传入一个邻接矩阵表示的无向图,来计算出最小的长度。其中,`graph`是一个二维列表,表示的邻接矩阵,如果两个顶点之间没有边,则对应位置的值为0。 注意,这里的最小指的是由三个顶点组成的,并且每个顶点都与相邻的两个顶点相连。如果中不存在这样的,则返回无穷大(INF)。 希望能够帮助到你!如有更多问题,请继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值