//poj 2112 网络流
//
//学会用二分答案再测是否满流的方法解题
//过了
//二分思想
//为0 的边即不可到的边,除自环,则要化为inf
//floyed判inf的优化
//
//题目大意是:K台挤奶机器,C头牛,K不超过30,C不超过200,每台挤奶机器最多可以为M台牛工作,给出这些牛和机器之间,牛和牛之间,
//机器与机器之间的距离,在保证让最多的牛都有机器挤奶的情况下,给出其中最长的一头牛移动的距离的最小值。
//
//首先用Floyd求出任意两点之间的最短距离,然后再用二分法限定最多的移动距离d,在求最大流时,搜索增广路的时候同时也判断距离有没有超过d就行了。
//分清哪个变量的意义。别弄混,建错图
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
#include<string>
#define maxn 300
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f
using namespace std;
int s,dest;
int c,m,k;
int d[maxn][maxn];
int w[maxn][maxn];
struct Dinic
{
int edgeNum,source,sink;
bool vis[maxn];
int d[maxn];
int cur[maxn];
int mark[maxn];
struct edge
{
int from,to,cap,flow;
};
vector<edge> edges;
vector<int> mapt[maxn];
void addEdge(int from,int to,int cap){
//pf("%d %d %d\n",from,to,cap);
edges.push_back((edge){from,to,cap,0});
edges.push_back((edge){to,from,0,0});
edgeNum = edges.size();
mapt[from].push_back(edgeNum-2);
mapt[to].push_back(edgeNum-1);
}
bool bfs()
{
memset(vis,0,sizeof vis);
queue<int> q;
q.push(source);
d[source] =0; vis[source] =1;
while(!q.empty()){
int x = q.front(); q.pop();
for(int i=0;i<mapt[x].size();i++){
edge& e = edges[mapt[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to] = 1;
d[e.to] = d[x] +1;
q.push(e.to);
}
}
}
return vis[sink];
}
int dfs(int x,int a){
if(x==sink||a==0) return a;
int flow=0,f;
for(int& i=cur[x];i<mapt[x].size();i++){
edge& e = edges[mapt[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow += f;
edges[mapt[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a==0) break;
}
}
return flow;
}
int maxFlow(int source,int sink){
this->sink = sink; this->source = source;
int flow = 0;
while(bfs()){
memset(cur,0,sizeof cur);
flow += dfs(source,INF);
}
return flow;
}
};
///floyed里无边的应该化为inf
void floyed(int n)
{
// for(int i=1;i<=n;i++)
// {
/// for(int j=1;j<=n;j++)
// cout<<d[i][j]<<" ";
// cout<<endl;
// }
for(int t=1;t<=n;t++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int temp=d[i][t]+d[t][j];
if(temp<d[i][j])
d[i][j]=temp;
}
//for(int i=1;i<=n;i++)
// for(int j=1;j<=n;j++)
// cout<<d[i][j]<<" dis "<<endl;
}
bool build(int bound)
{
Dinic dinic;
for(int i=1;i<=c;i++)
{
dinic.addEdge(s,i,1);
// cout<<s<<" addedge "<<i<<endl;
}
for(int i=1;i<=c;i++)
for(int j=1;j<=k;j++)
if(w[i][j]<=bound)
{
dinic.addEdge(i,c+j,1);
//cout<<i<<" addedge "<<c+j<<endl;
}
for(int i=1;i<=k;i++)
{
//cout<<c+i<<" addedge"<<dest<<endl;
dinic.addEdge(c+i,dest,m);
}
int ans=dinic.maxFlow(s,dest);
if(ans==c)
return true;
else
return false;
}
int main()
///k为机器数,c为奶牛数,m为每台机器每天工作的奶牛数的上线
{
while(scanf("%d%d%d",&k,&c,&m)!=EOF)
{
int temp=k+c;
for(int i=1;i<=temp;i++)
for(int j=1;j<=temp;j++)
{
scanf("%d",&d[i][j]);
if(d[i][j]==0 && i!=j)
d[i][j]=inf;
}
floyed(temp);
int ma=0;
int mi=inf;
for(int i=k+1;i<=temp;i++)
for(int j=1;j<=k;j++)
{
w[i-k][j]=d[i][j];
if(w[i-k][j]>ma) ma=w[i-k][j];
if(w[i-k][j]<mi) mi=w[i-k][j];
// cout<<i-k<<" "<<j<<" "<<w[i-k][j]<<endl;
}
s=0;
dest=temp+1;
int left=mi;
int right=ma;
int mid;
//cout<<ma<<" "<<mi<<endl;
// cout<<"miao"<<build(1)<<endl;
int ans;
while(left<=right)
{
mid=(left+right)>>1;
// cout<<mid<<" * "<<build(mid)<<endl;
if(build(mid))
{
ans=mid;
right=mid-1;
}
else
left=mid+1;
}
cout<<ans<<endl;
}
}
//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
POJ 2112 网络流加二分
最新推荐文章于 2019-10-11 09:48:02 发布