标签:style class blog http tar ext
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2879
题意:有n道菜,每道菜需要b[i]份,m个厨师,第j个厨师做第i道菜需要时间a[i][j],求做完所有菜,所有人等待的最小总时间。
思路:设所有的菜为sum。一个明显的思路是将每个厨师拆成sum个点。然后sum个菜每个菜向每个厨师的每个点连边,表示该道菜为该厨师第几个做。由于这样数据太大。动态加边。每次增光一次后找到此次增广的厨师,每道菜将其连边。
struct node
{
int u,v,next,cost,cap;
};
node edges[N*5];
int head[N],e;
void add(int u,int v,int cap,int cost)
{
e++;
edges[e].u=u;
edges[e].v=v;
edges[e].cap=cap;
edges[e].cost=cost;
edges[e].next=head[u];
head[u]=e;
}
void Add(int u,int v,int cap,int cost)
{
add(u,v,cap,cost);
add(v,u,0,-cost);
}
int pre[N],F[N],C[N],visit[N];
int SPFA(int s,int t,int n)
{
int i;
for(i=0;i<=n;i++) F[i]=0,C[i]=INF,visit[i]=0;
queue<int> Q;
Q.push(s); F[s]=INF; C[s]=0;
int u,v,cost,cap;
while(!Q.empty())
{
u=Q.front();
Q.pop();
visit[u]=0;
for(i=head[u];i;i=edges[i].next)
{
if(edges[i].cap>0)
{
v=edges[i].v;
cost=edges[i].cost;
cap=edges[i].cap;
if(C[v]>C[u]+cost)
{
C[v]=C[u]+cost;
F[v]=min(F[u],cap);
pre[v]=i;
if(!visit[v]) visit[v]=1,Q.push(v);
}
}
}
}
return F[t];
}
int s,t,n,m,a[55][105],b[105],cnt[105],last[105];
int main()
{
RD(n,m);
int sum=0,i,j,x;
FOR1(i,n) RD(b[i]),sum+=b[i];
e=1;
s=0; t=n+m+sum+1;
FOR1(i,n)
{
Add(s,i,b[i],0);
FOR1(j,m)
{
RD(a[i][j]);
Add(i,n+j,1,a[i][j]);
}
}
FOR1(i,m)
{
cnt[i]=1;
Add(n+i,t,1,0);
last[i]=e;
}
int ans=0,temp;
while(sum--)
{
temp=SPFA(s,t,t);
for(i=t;i!=s;i=edges[pre[i]].u)
{
x=pre[i];
ans+=temp*edges[x].cost;
edges[x].cap-=temp;
edges[x^1].cap+=temp;
}
for(j=1;j<=m&&edges[last[j]-1].cap;j++);
cnt[j]++;
FOR1(i,n) Add(i,n+m+sum,1,a[i][j]*cnt[j]);
Add(n+m+sum,t,1,0);
last[j]=e;
}
PR(ans);
}
BZOJ 2879 美食节(费用流-动态加边),布布扣,bubuko.com
标签:style class blog http tar ext
原文地址:http://www.cnblogs.com/jianglangcaijin/p/3799730.html