Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 13910 | Accepted: 5023 | |
Case Time Limit: 1000MS |
Description
Input
Output
Sample Input
2 3 2 0 3 2 1 1 3 0 3 2 0 2 3 0 1 0 1 2 1 0 2 1 0 0 2 0
Sample Output
2
题意:有C头奶牛和K台挤奶机,已知每台挤奶机只能给M头牛挤奶。奶牛编号从K+1 到 K+C,挤奶机编号从1 到 K。我们把奶牛和挤奶机看作K+C个点,现在给你一个 (K + C) * (K + C)的矩阵,矩阵第 i 行 第 j 列 的元素代表第i个点到第j个点的距离。显然的,如果要给一头奶牛挤奶,则需要这头奶牛走到挤奶机(任意一个都行)的位置。现在让你设计一种方案:安排给每头奶牛挤奶的,使得C头奶牛需要行走的路程中的最大路程最小。
简单最大流题目,我却WA了那么多次。不会再爱了。。。 以后写Floyd再不也用0来表示 两点间没有路了。
思路:1,首先Floyd预处理最短路。2,然后二分查找最优距离并以当前查找距离为限制建新图。3,接着超级源到超级汇跑一次最大流判断是否满流,若满流压缩距离,否则增大距离。4,继续二分查找 延续上面过程。
对当前查找的距离mid建图如下(不说太细了,建图思路没有违反常理。。。)
一:如果奶牛i到挤奶机j的距离不大于mid,则建边i -> j容量为1。
二:超级源点到每头奶牛建边,容量为1。
三:每台挤奶机到超级汇点建边,容量为M。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <stack> #include <algorithm> #define MAXN 300 #define MAXM 200000 #define INF 10000000 using namespace std; struct Edge { int from, to, cap, flow, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int cur[MAXN]; int dist[MAXN]; bool vis[MAXN]; int Map[300][300]; int K, C, M; void Floyd()//预处理最短距离 { for(int k = 1; k <= K + C; k++) { for(int i = 1; i <= K + C; i++) { if(Map[i][k] == INF) continue; for(int j = 1; j <= K + C; j++) { //if(Map[k][j] == 0 || Map[i][j] == 0) continue; Map[i][j] = min(Map[i][j], Map[i][k] + Map[k][j]); } } } } void input() { for(int i = 1; i <= K + C; i++) { for(int j = 1; j <= K + C; j++) { scanf("%d", &Map[i][j]); if(Map[i][j] == 0) Map[i][j] = INF; } } Floyd(); } void init() { memset(head, -1, sizeof(head)); edgenum = 0; } void addEdge(int u, int v, int w) { Edge E1 = {u, v, w, 0, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } void getMap(int mid) { for(int i = K + 1; i <= K + C; i++)//遍历 { for(int j = 1; j <= K; j++) { if(Map[i][j] <= mid) addEdge(i, j, 1);//奶牛引一条容量为1的边到挤奶器 } } for(int i = 1; i <= K + C; i++) { if(i >= K + 1) addEdge(0, i, 1);//超级源点引一条到 每头牛的边 容量为1 if(i <= K) addEdge(i, K + C + 1, M);//挤奶器到超级汇点 建边。 } } bool BFS(int start, int end) { queue<int> Q; memset(dist, -1, sizeof(dist)); memset(vis, false, sizeof(vis)); dist[start] = 0; vis[start] = true; Q.push(start); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(!vis[E.to] && E.cap > E.flow) { vis[E.to] = true; dist[E.to] = dist[u] + 1; if(E.to == end) return true; Q.push(E.to); } } } return false; } int DFS(int x, int a, int end) { if(x == end || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = edge[i].next) { Edge &E = edge[i]; if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(E.cap - E.flow, a), end)) > 0) { E.flow += f; edge[i^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int start, int end) { int flow = 0; while(BFS(start, end)) { memcpy(cur, head, sizeof(head)); flow += DFS(start, INF, end); } return flow; } void solve() { int left = 0, right = 1000000, mid, ans; while(right >= left) { mid = (left + right) >> 1;//每次建图的最大距离 init(); getMap(mid); if(Maxflow(0, K + C + 1) == C)//每头奶牛都能挤上奶 满流 { ans = mid; right = mid - 1; } else left = mid + 1; } printf("%d\n", ans); } int main() { while(scanf("%d%d%d", &K, &C, &M) != EOF) { input(); solve(); } return 0; }