题目链接:
题意:
Fj有k个挤奶器,和c头奶牛,每个挤奶器每天可以帮助M头奶牛挤奶,给出k个挤奶器和c头牛两两之间距离的邻接矩阵,求完成所有奶牛挤奶工作,(某个奶牛)需要移动的最大距离的最小值。
题解思路:
1.floyed算法求出每头奶牛到每个挤奶器的最短距离
2.二分枚举需要移动的最大值
用网络流判断这个最大值可行
可行则继续枚举更小的移动距离
如果不可行则枚举更大的移动距离
1。建立源点,连接所有挤奶器,权值为每天可帮助的奶牛数
2。建立汇点,连接每头奶牛,权值为1
3。如果奶牛到挤奶器的距离小于枚举得到的距离,则创建一条挤奶器到奶牛的边,权值为1
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxx 0x3f3f3f
#define M 305
using namespace std;
int dis[M][M];
int arc[M][M];
int level[M];
int n,m,k,s;
int min(int a,int b)
{
return a<b?a:b;
}
void floyed()
{
for(int k=1; k<=s; k++)
for(int i=1; i<=s; i++)
for(int j=1; j<=s; j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
return;
}
void creat_G(int max_len)
{
memset(arc,0,sizeof(arc));
for(int i=1; i<=n; i++)
arc[i][s+1]=k;
for(int i=n+1; i<=s; i++)
arc[0][i]=1;
for(int i=1; i<=n; i++)
for(int j=n+1; j<=s; j++)
if(dis[i][j]<=max_len)
arc[j][i]=1;
return ;
}
int bfs()
{
memset(level,-1,sizeof(level));
int q[M];
int head=0,tail=0,v;
level[0]=0;
q[tail++]=0;
while(head<tail)
{
v=q[head++];
for(int i=1; i<=s+1; i++)
if(level[i]==-1&&arc[v][i])
{
level[i]=level[v]+1;
q[tail++]=i;
}
}
return level[s+1]!=-1;
}
int dfs(int loc,int flow)
{
int unused=flow;
if(flow==0||loc==s+1)
return flow;
for(int i=1;i<=s+1;i++)
if(level[i]==level[loc]+1&&arc[loc][i])
{
int used=dfs(i,min(unused,arc[loc][i]));
arc[loc][i]-=used;
arc[i][loc]+=used;
unused-=used;
}
return flow-unused;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
{
s=n+m;
for(int i=1; i<=s; i++)
for(int j=1; j<=s; j++)
{
scanf("%d",&dis[i][j]);
if(dis[i][j]==0)
dis[i][j]=maxx;
}
floyed();
int l=1,r=20005,mid;
while(l<r)
{
mid=(l+r)/2;
creat_G(mid);
int ans=0;
while(bfs())
ans+=dfs(0,maxx);
if(ans>=m)
r=mid;
else
l=mid+1;
}
cout<<r<<endl;
}
return 0;
}
补上isap模板
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
const int MAXN =305;
const int MAXM=440020;
const int INF=0x3f3f3f3f;
using namespace std;
struct Edge {
int to,cap,flow,next;
} edge[MAXM];
int head[MAXN],tot,gap[MAXN],d[MAXN],cur[MAXN],que[MAXN],p[MAXN];
int K,c,m,ss;
void addedge(int u,int v,int c,int f)
{
edge[tot]=(Edge){v,c,f,head[u]};
head[u] = tot++;
edge[tot]=(Edge){u,c,c,head[v]};
head[v] = tot++;
}
int isap(int source,int sink,int N)
{
memset(gap,0,sizeof(gap));
memset(d,0,sizeof(d));
memcpy(cur,head,sizeof(head));
int top = 0,x = source,flow = 0;
while(d[source] < N) {
if(x == sink) {
int Min = INF,inser=0;
for(int i = 0; i < top; ++i) {
if(Min > edge[p[i]].cap - edge[p[i]].flow) {
Min = edge[p[i]].cap - edge[p[i]].flow;
inser = i;
}
}
for(int i = 0; i < top; ++i) {
edge[p[i]].flow += Min;
edge[p[i]^1].flow -= Min;
}
if(Min!=INF) flow += Min;
top = inser;
x = edge[p[top]^1].to;
continue;
}
int ok = 0;
for(int i = cur[x]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(edge[i].cap > edge[i].flow && d[v]+1 == d[x]) {
ok = 1;
cur[x] = i;
p[top++] = i;
x = edge[i].to;
break;
}
}
if(!ok) {
int Min = N;
for(int i = head[x]; i != -1; i = edge[i].next) {
if(edge[i].cap > edge[i].flow && d[edge[i].to] < Min) {
Min = d[edge[i].to];
cur[x] = i;
}
}
if(--gap[d[x]] == 0) break;
gap[d[x] = Min+1]++;
if(x != source) x = edge[p[--top]^1].to;
}
}
return flow;
}
int dis[MAXN][MAXN];
void build(int v)
{
tot=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=K;i++)
addedge(0,i,m,0);
for(int i=1;i<=K;i++)
for(int j=K+1;j<=ss;j++)
if(dis[i][j]<=v)
addedge(i,j,1,0);
for(int j=K+1;j<=ss;j++)
addedge(j,ss+1,1,0);
}
int main()
{
scanf("%d%d%d",&K,&c,&m);
ss=K+c;
for(int i=1;i<=ss;i++)
for(int j=1;j<=ss;j++){
scanf("%d",&dis[i][j]);
if(!dis[i][j])
dis[i][j]=INF;
}
for(int k=1;k<=ss;k++)
for(int i=1;i<=ss;i++)
for(int j=1;j<=ss;j++)
if(dis[i][k]+dis[k][j]<dis[i][j])
dis[i][j]=dis[i][k]+dis[k][j];
int l=0,r=100000,mid;
int ans,d;
while(l<=r)
{
mid=(l+r)>>1;
build(mid);
d=isap(0,ss+1,ss+2);
if(d>=c)
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%d\n",ans);
return 0;
}
: