您的位置:首页 > 其它

poj2112 二分+floyd+最大流 好题

2016-03-05 15:46 309 查看
  这个题的意思是有K个挤奶机器, 和C个牛,一个机器每天最多服务W个奶牛, 如果将牛和机器看成顶点那么告诉两顶点之间的距离, 那么请最小化奶牛去挤奶的时候走的路的最大值, 首先我们可以使用floyd求出奶牛去某个挤奶机器的最短路径,然后二分一个答案, 建图, 我们再定义一个超级源点和超级汇点, 源点指向机器, 权值为W, 机器和奶牛之间也有边, 满足条件为边的长度小于等于二分的答案, 权值为1, 每个奶牛到汇点也有一个边权值为1, 求出此图的最大流观察其是否等于奶牛的数量, 代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;
int K, C, M;
int d[250][250];

const int maxn = 500;
const int inf = 0x3f3f3f3f;

struct Dinic
{
int n;       //n个顶点
struct edge
{
int from, to, cap;
};
vector<int> G[maxn];
vector<edge> e;
int level[maxn], iter[maxn];

void init()
{
for(int i=0; i<=n; i++) G[i].clear();
e.clear();
}

void add_edge(int u, int v, int cap)
{
e.push_back((edge)
{
u, v, cap
});
e.push_back((edge)
{
v, u, 0
});
int m = e.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}

void bfs(int s)
{
memset(level, -1, sizeof(level));
queue<int> que;
level[s] = 0;
que.push(s);
while(!que.empty())
{
int u = que.front();
que.pop();
for(int i=0; i<G[u].size(); i++)
{
edge &te = e[G[u][i]];
if(te.cap>0 && level[te.to]<0)
{
level[te.to] = level[u] + 1;
que.push(te.to);
}
}
}
}

int dfs(int v, int t, int f)
{
if(v == t) return f;
for(int &i=iter[v]; i<G[v].size(); i++)
{
edge &tpe = e[G[v][i]];
if(tpe.cap>0 && level[v]<level[tpe.to])
{
int d = dfs(tpe.to, t, min(f, tpe.cap));
if(d > 0)
{
tpe.cap -= d;
e[G[v][i]^1].cap += d;
return d;
}
}
}
return 0;
}

int max_flow(int s, int t)
{
int flow = 0;
for(;;)
{
bfs(s);
if(level[t]<0) return flow;
memset(iter, 0, sizeof(iter));
int f;
while((f=dfs(s, t, 0x3fffffff)) > 0)
flow += f;
}
}
} di;

void floyd()
{
int n = K+C;
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
}

bool check(int mid)
{
di.n = K+C+2;   //0超级源点 machine 1-K cow K+1-K+C  K+C+1超级汇点
di.init();
for(int i=1; i<=K; i++)       //机器
{
for(int j=1+K; j<=C+K; j++)   if(d[i][j]<=mid) //奶牛
{
int u=i, v=j;
di.add_edge(u, v, 1);
}
di.add_edge(0, i, M);
}
for(int j=1; j<=C; j++) di.add_edge(K+j, K+C+1, 1);
int f = di.max_flow(0, K+C+1);
return f==C;
}

int main()
{
while(scanf("%d%d%d", &K, &C, &M)==3)
{
for(int i=1; i<=K+C; i++)
for(int j=1; j<=K+C; j++)
{
scanf("%d", &d[i][j]);
if(i!=j && d[i][j]==0) d[i][j] = inf;
}
floyd();
int l=0, r=100000;
int ans;

while(l <= r)
{
int mid = (l+r)/2;
if(check(mid))
{
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
printf("%d\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: