因为每个点只能经过一次 所以考虑拆点

这题有坑,有重边。。

KM算法

把一个点拆成入点和出点 入点在X部,出点在Y步。

如果u,v之间有路径,就在X部的u点连接Y部的v点

求完美匹配。

当完美匹配的时候,每个点都有一个入度和一个出度,可知成环。

因为完美匹配求得是最大匹配

记得把每条边权值取相反数

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;
const int MAXN = 205;
const int INF = 0x3f3f3f3f;

int G[MAXN][MAXN];
int vx[MAXN], vy[MAXN];
bool visx[MAXN], visy[MAXN];
int match[MAXN];
int slack[MAXN];

int N, M;

bool dfs(int x)
{
    visx[x] = true;

    for (int y = 0; y < N; ++y) {

        if (visy[y]) continue;

        int gap = vx[x] + vy[y] - G[x][y];

        if (gap == 0) {
            visy[y] = true;
            if (match[y] == -1 || dfs( match[y] )) {
                match[y] = x;
                return true;
            }
        } else {
            slack[y] = min(slack[y], gap);
        }
    }

    return false;
}

int KM()
{
    memset(match, -1, sizeof match);
    memset(vy, 0, sizeof vy);

    for (int i = 0; i < N; ++i) {
        vx[i] = G[i][0];
        for (int j = 1; j < N; ++j) {
            vx[i] = max(vx[i], G[i][j]);
        }
    }

    for (int i = 0; i < N; ++i) {

        fill(slack, slack + N, INF);

        while (1) {
            memset(visx, false, sizeof visx);
            memset(visy, false, sizeof visy);

            if (dfs(i)) break;

            int d = INF;
            for (int j = 0; j < N; ++j)
                if (!visy[j]) d = min(d, slack[j]);

            for (int j = 0; j < N; ++j) {
                if (visx[j]) vx[j] -= d;
                if (visy[j]) vy[j] += d;
                else slack[j] -= d;
            }
        }
    }

    int res = 0;
    for (int i = 0; i < N; ++i)
        res += G[ match[i] ][i];

    return res;
}

int Scan() {
    int res = 0, flag = 0;
    char ch;
    if((ch = getchar()) == '-') flag = 1;
    else if(ch >= '0' && ch <= '9') res = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9')
        res = res * 10 + (ch - '0');
    return flag ? -res : res;
}

int main()
{
    int T = Scan();
    while (T--) {
        N = Scan(), M = Scan();
        for (int i = 0; i <= N; ++i) {
            for (int j = 0; j <= N; ++j) {
                G[i][j] = -INF;
            }
        }
        int u, v, w;
        while (M--) {
            u = Scan()-1, v = Scan()-1, w = Scan();
            G[u][v] = max(G[u][v], -w);
        }

        printf("%d\n", -KM());
    }
    return 0;
}
View Code

相关文章:

  • 2021-10-20
  • 2021-11-08
  • 2022-12-23
  • 2021-09-08
  • 2021-06-15
  • 2022-12-23
  • 2022-02-24
  • 2022-12-23
猜你喜欢
  • 2021-07-26
  • 2021-05-20
  • 2021-05-23
  • 2021-07-24
  • 2021-06-15
  • 2022-01-19
  • 2022-02-25
相关资源
相似解决方案