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
#include
#include
#include
#include
#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 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;
}