题意:
无向图输出最小环上的边
思路:
可以按权值从小到大加边,直到出现环,之后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;
}
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;
}