您的位置:首页 > 其它

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

2016-07-19 00:09 411 查看
题目链接:点击打开链接

题目大意:在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 | 1
const 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息