KM算法

1.朴素KM 时间复杂度:$O(n^4)$

算法过程:

  1. 初始化可行顶标的值 (设定lx,ly的初始值)
  2. 用匈牙利算法寻找相等子图的完备匹配
  3. 若未找到增广路则修改可行顶标的值
  4. 重复(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;
}

 

posted @ 2020-08-01 02:32  无知的博士  阅读(205)  评论(0)    收藏  举报