POJ 2112:二分搜索 + 二分图多重匹配 + 最短路径
最近,在复习一些图论的算法,找了些图论的题做一下。POJ 2112这题挺有代表性的,用到蛮多知识点。
题目:http://acm.pku.edu.cn/JudgeOnline/problem?id=2112
解题思路:求得每只牛与各机器的最短距离(Floyd);二分解空间;用修改后的匈牙利算法看C只牛是否能被完全匹配来判断解的可行性。
#include <cstring> #include <cstdio> namespace std{} using namespace std; #define INF 100000000 int dis[232][232], link[31][16], vlink[31], k, c, m, s; bool g[31][201], b[31]; void input() { scanf("%d%d%d", &k, &c, &m); s = k + c; for(int i = 0; i < s; ++i) for(int j = 0; j < s; ++j) { scanf("%d", &dis[i][j]); if(dis[i][j] == 0) dis[i][j] = INF; } } void floyd() { for(int x = 0; x < s; ++x) for(int i = 0; i < s; ++i) for(int j = 0; j < s; ++j) if(dis[i][j] > dis[i][x] + dis[x][j]) dis[i][j] = dis[i][x] + dis[x][j]; } bool findroad(int p) { for(int i = 0; i < k; ++i) { if(g[i][p] && !b[i]) { b[i] = true; if(vlink[i] < m) { link[i][vlink[i]++] = p; return true; } for(int j = 0; j < vlink[i]; ++j) if(findroad(link[i][j])) { link[i][j] = p; return true; } } } return false; } bool isOK(int mid) { int i, j; memset(g, false, sizeof(g)); memset(link, 0, sizeof(link)); memset(vlink, 0, sizeof(vlink)); for(i = 0; i < k; ++i) for(j = k; j < s; ++j) if(dis[i][j] <= mid) g[i][j - k] = true; for(i = 0; i < c; ++i) { memset(b, false, sizeof(b)); if(!findroad(i)) return false; } return true; } void binary_search() { int min, max, mid; min = max = 0; for(int i = 0; i < k; ++i) for(int j = k; j < s; ++j) max = (dis[i][j] > max) ? dis[i][j] : max; while(min < max) { mid = (min + max) / 2; if(isOK(mid)) { max = mid; } else { min = mid + 1; } } printf("%d/n", max); } int main() { input(); floyd(); binary_search(); return 0; }