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求出二分图的最大权匹配。
题目大意:在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; }
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法