传送门
题意:有k个挤奶机,c个奶牛,每个挤奶机可以挤m只,给i你一张邻接矩阵,问走最远的奶牛最少要走多远到挤奶机。
思路:呵呵了,一开始想成费用流了,结果一直wa,后来才发现费用流只能保证总费用最小,而不能使其中增广路费用的最大值最小,傻逼了。
在wa的无法自拔的时候,看了一眼芳哥博客,说是二分和最大流,瞬间明白了,这里就是二分枚举答案,看在这个最远值之内能否达到最大流,然后求出最小的能达到最大流的答案。
反思:没能仔细读题,对于i!=j的0距离,代表不能直接到达。。。。。没看仔细。。。。。哎~~~~。后来才加了floyed过了。
#include
#include
#include
#include
#define maxn 1<<29
using namespace std;
int fst[250],next[20000],node[20000],l[20000],cc[20000];
int c,k,m,en,ans,d[250],pre[250],f[20000],lu[250];
int a[300][300],flow;
bool vi[250];
void add(int u,int v,int con,int fee)
{
next[en]=fst[u];
fst[u]=en;
node[en]=v;
cc[en]=con;
l[en]=fee;
en++;
}
bool bfs(int s,int t,int ml)
{
memset(vi,0,sizeof(vi));
queueq;
q.push(s);
vi[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=fst[u];i!=-1;i=next[i])
{
int v=node[i];
if(cc[i]>f[i]&&l[i]<=ml&&!vi[v])
{
pre[v]=u;
lu[v]=i;
vi[v]=1;
if(v==t)return true;
q.push(v);
}
}
}
return false;
}
void ek(int s,int t,int ml)
{
memset(f,0,sizeof(f));
while(bfs(s,t,ml))
{
for(int i=t;i!=s;i=pre[i])
{
int v=lu[i];
f[v]+=1;
f[v^1]-=1;
}
flow+=1;
}
}
void solve()
{
int left=0,right=20000,mid;
while(left<=right)
{
mid=(left+right)/2;
flow=0;
ek(0,k+c+1,mid);
if(flow==c)
{
ans=mid;
right=mid-1;
}
else left=mid+1;
}
}
int main()
{
while(scanf("%d%d%d",&k,&c,&m)!=EOF)
{
en=0;
memset(fst,-1,sizeof(fst));
int sum=k+c;
for(int i=1; i<=sum; i++)
{
for(int j=1; j<=sum; j++)
{
scanf("%d",&a[i][j]);
if(i!=j&&a[i][j]==0)a[i][j]=maxn;
}
}
for(int x=1;x<=sum;x++)
{
for(int y=1;y<=sum;y++)
{
for(int z=1;z<=sum;z++)
{
if(a[y][z]>a[y][x]+a[x][z])a[y][z]=a[y][x]+a[x][z];
}
}
}
for(int i=1; i<=k; i++)
{
for(int j=1; j<=c; j++)
{
add(i,k+j,1,a[i][k+j]);
add(k+j,i,0,a[k+j][i]);
}
add(0,i,m,0);
add(i,0,0,0);
}
for(int i=1; i<=c; i++)
{
add(k+i,sum+1,1,0);
add(sum+1,k+i,0,0);
}
solve();
cout<