传送门
题意:有k个挤奶机,c个奶牛,每个挤奶机可以挤m只,给i你一张邻接矩阵,问走最远的奶牛最少要走多远到挤奶机。
思路:呵呵了,一开始想成费用流了,结果一直wa,后来才发现费用流只能保证总费用最小,而不能使其中增广路费用的最大值最小,傻逼了。
在wa的无法自拔的时候,看了一眼芳哥博客,说是二分和最大流,瞬间明白了,这里就是二分枚举答案,看在这个最远值之内能否达到最大流,然后求出最小的能达到最大流的答案。
反思:没能仔细读题,对于i!=j的0距离,代表不能直接到达。。。。。没看仔细。。。。。哎~~~~。后来才加了floyed过了。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #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)); queue<int>q; 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<<ans<<endl; } return 0; }