HDU 2448 Mining Station on the Sea(floyd+KM)

来源:互联网 发布:papago翻译软件 编辑:程序博客网 时间:2024/05/17 08:24

题目链接:点击打开链接

题目大意:在m个采矿站中有n只船,这n只船要回到n个港口,每个港口只能停留有一只船。给出距离,求这n只船全部回到港口要走的总路程的最小值。

最短路+最小权匹配,两部分都是非常裸的。

先用floyd求出m个采矿站到n个港口的最短路程。题目中有这么一句话:“Notice that once the ship entered the port, it will not come out!”,所以使用floyd的时候要注意港口不能作为中间点。然后再用KM求出二分图的最大权匹配。

#include <set>#include <map>#include <cmath>#include <stack>#include <queue>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;#define FIN freopen("in.txt", "r", stdin);#define FOUT freopen("out.txt", "w", stdout);#define lson l, mid, cur << 1#define rson mid + 1, r, cur << 1 | 1const int INF = 0x3f3f3f3f;const int MAXN = 3e2 + 50;int n, m, k, p, loc[MAXN], dis[MAXN][MAXN];int nx, ny, linker[MAXN], lx[MAXN], ly[MAXN], slack[MAXN], G[MAXN][MAXN];bool visx[MAXN], visy[MAXN];bool dfs(int x){    visx[x] = true;    for (int y = 1; y <= ny; y++)    {        if (visy[y])            continue;        int tmp = lx[x] + ly[y] - G[x][y];        if (tmp == 0)        {            visy[y] = true;            if (linker[y] == -1 || dfs(linker[y]))            {                linker[y] = x;                return true;            }        }        else            slack[y] = min(slack[y], tmp);    }    return false;}int KM(){    memset(linker, -1, sizeof(linker));    memset(ly, 0, sizeof(ly));    for (int x = 1; x <= nx; x++)    {        lx[x] = -INF;        for (int y = 1; y <= ny; y++)            lx[x] = max(lx[x], G[x][y]);    }    for (int x = 1; x <= nx; x++)    {        for (int i = 1; i <= ny; i++)            slack[i] = INF;        while (true)        {            memset(visx, false, sizeof(visx));            memset(visy, false, sizeof(visy));            if (dfs(x))                break;            int d = INF;            for (int i = 1; i <= ny; i++)                if (!visy[i])                    d = min(d, slack[i]);            for (int i = 1; i <= nx; i++)                if (visx[i])                    lx[i] -= d;            for (int i = 1; i <= ny; i++)                if (visy[i])                    ly[i] += d;                else                    slack[i] -= d;        }    }    int res = 0;    for (int i = 1; i <= ny; i++)        if (linker[i] != -1)            res += G[linker[i]][i];    return res;}void floyd(){    for (int k = n + 1; k <= n + m; k++) //港口的编号为1~n,不能作为中间点        for (int i = 1; i <= n + m; i++)            for (int j = 1; j <= n + m; j++)                if (dis[i][k] != INF && dis[k][j] != INF)                    dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);}int main(){#ifndef ONLINE_JUDGE    FIN;#endif // ONLINE_JUDGE    while (~scanf("%d%d%d%d", &n, &m, &k, &p))    {        nx = ny = n;        for (int i = 1; i <= n + m; i++)            for (int j = 1; j <= n + m; j++)            {                if (i == j)                    dis[i][j] = 0;                else                    dis[i][j] = INF;                G[i][j] = 0;            }        for (int i = 1; i <= n; i++)        {            scanf("%d", &loc[i]);            loc[i] += n; //港口编号为1~n,采矿站编号为n+1~n+m        }        for (int i = 0; i < k; i++)        {            int a, b, c;            scanf("%d%d%d", &a, &b, &c);            dis[a + n][b + n] = dis[b + n][a + n] = c;        }        for (int i = 0; i < p; i++)        {            int d, e, f;            scanf("%d%d%d", &d, &e, &f);            dis[d][e + n] = dis[e + n][d] = f;        }        floyd();        for (int i = 1; i <= nx; i++)            for (int j = 1; j <= ny; j++)                G[i][j] = -dis[j][loc[i]];        printf("%d\n", -KM());    }    return 0;}


0 0