KM算法
1.朴素KM 时间复杂度:$O(n^4)$
算法过程:
- 初始化可行顶标的值 (设定lx,ly的初始值)
- 用匈牙利算法寻找相等子图的完备匹配
- 若未找到增广路则修改可行顶标的值
- 重复(2)(3)直到找到相等子图的完备匹配为止
板子:
#pragma GCC optimize(3) #pragma GCC optimize(2) #include <iostream> #include <string> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <functional> #include <vector> #include <map> #include <set> #include <stack> #include <fstream> #include <sstream> #include <unordered_map> #define FT(a, b) memset(a, b, sizeof(a)) #define FAT(a) memset(a, 0, sizeof(a)) using namespace std; typedef long long ll; const int N = 5e2 + 10; const int M = 1e5 + 100; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int n, m, k, x, y, t; int g[N][N], lx[N], ly[N], visx[N], visy[N], match[N]; bool findpath(int x) { for (int i = 1; i < n + 1; ++i) { if (visy[i] || lx[x] + ly[i] != g[x][i]) continue; visy[i] = 1; if (match[i] == -1 || findpath(match[i])) { match[i] = x; return 1; } } return 0; } ll km() { ll ans = 0; for (int i = 1; i < n + 1; ++i) { while (1) { FAT(visx), FAT(visy); int delta = INF; if (findpath(i)) break; else { for (int i = 1; i < n + 1; ++i) if (visx[i]) for (int j = 1; j < n + 1; ++j) if (visy[j]) delta = min(delta, lx[i] + ly[j] - g[i][j]); for (int i = 1; i < n + 1; ++i) { if (visx[i]) lx[i] -= delta; if (visy[i]) ly[i] += delta; } } } } for (int i = 1; i < n + 1; ++i) ans += g[match[i]][i]; return ans; } void solve() { scanf("%d%d", &n, &m); FAT(lx), FAT(ly); FT(g, INF), FT(match, -1); for (int i = 0; i < m; ++i) { int a, b, c; scanf("%d%d%d", &a, &b, &c); g[a][b] = c; lx[a] = max(lx[a], c); } printf("%lld\n", km()); for (int i = 1; i < n + 1; ++i) printf("%d ", match[i]); puts(""); } int main() { #ifdef ONLINE_JUDGE #else freopen("/home/wjy/code/in.txt", "r", stdin); // freopen("/home/wjy/code/ans1.txt","w", stdout); #endif ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int T = 1; // scanf("%d", &T); // cin >> T; // time_t begin, end; // begin = clock(); while (T--) { solve(); } // end = clock(); // double ret = double(end - begin) / CLOCKS_PER_SEC; return 0; }
$O(n^3)$的板子
#pragma GCC optimize(3) #pragma GCC optimize(2) #include <iostream> #include <string> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <functional> #include <vector> #include <map> #include <set> #include <stack> #include <fstream> #include <sstream> #include <unordered_map> #define FT(a, b) memset(a, b, sizeof(a)) #define FAT(a) memset(a, 0, sizeof(a)) using namespace std; typedef long long ll; const int N = 5e2 + 10; const int M = 1e5 + 100; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int n, m, k, x, y, t; int g[N][N], lx[N], ly[N], vis[N], match[N], slack[N], pre[N]; void Bfs(int u) { FAT(pre), FT(slack, INF); int x, v = 0, vl, delta; match[v] = u; while (~match[v]) { x = match[v], delta = INF, vis[v] = 1; for (int i = 1; i <= n; ++i) if (!vis[i]) { if (slack[i] > lx[x] + ly[i] - g[x][i]) slack[i] = lx[x] + ly[i] - g[x][i], pre[i] = v; if (slack[i]<delta) delta = slack[i], vl = i; } for (int i = 0; i <= n; ++i) { if (vis[i]) lx[match[i]]-=delta, ly[i]+=delta; else slack[i]-=delta; } v = vl; } while (v) match[v] = match[pre[v]], v = pre[v]; } ll km() { ll ans = 0; FAT(lx), FAT(ly), FT(match, -1); for (int i = 1; i <= n; ++i) { FAT(vis); Bfs(i); } for (int i = 1; i <= n; ++i) ans += g[match[i]][i]; return ans; } void solve() { scanf("%d%d", &n, &m); for (int i = 1; i < n + 1; ++i) for (int j = 1; j < n + 1; ++j) g[i][j] = -INF; for (int i = 0; i < m; ++i) { int a, b, c; scanf("%d%d%d", &a, &b, &c); g[a][b] = c; } ll ans = km(); printf("%lld\n", ans); for (int i = 1; i < n + 1; ++i) printf("%d ", match[i]); puts(""); } int main() { #ifdef ONLINE_JUDGE #else freopen("/home/wjy/code/in.txt", "r", stdin); // freopen("/home/wjy/code/ans1.txt","w", stdout); #endif ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int T = 1; // scanf("%d", &T); // cin >> T; // time_t begin, end; // begin = clock(); while (T--) { solve(); } // end = clock(); // double ret = double(end - begin) / CLOCKS_PER_SEC; return 0; }

浙公网安备 33010602011771号