您的位置:首页 > 其它

bzoj 1061 志愿者招募 有上下界费用流做法

2016-12-22 09:26 246 查看
把每一天看作一个点,每一天的志愿者数目就是流量限制,从i到i+1连边,上下界就是(A[i],+inf)。

对于每一类志愿者,从T[i]+1到S[i]连边,费用为招募一个志愿者的费用,流量为inf。这样每多1的流量,就多了一个从S[i]到T[i]+1的循环流。

求一遍无源汇的最小费用可行流就可以了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
#define N 100005
using namespace std;
int n,m;
int v
;
int head
,ver
,nxt
,tot,f
,quan
;
void add(int a,int b,int c,int d)
{
tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;quan[tot]=d;f[tot]=c;
tot++;nxt[tot]=head[b];head[b]=tot;ver[tot]=a;quan[tot]=-d;f[tot]=0;
return ;
}
int S,T;
int dis[2005],in[2005],with[2005],mn[2005];
bool tell()
{
memset(dis,0x3f,sizeof(dis));
memset(in,0,sizeof(in));
dis[S]=0;mn[S]=inf;
queue<int>q;
q.push(S);
while(!q.empty())
{
int tmp=q.front();q.pop();in[tmp]=0;
for(int i=head[tmp];i;i=nxt[i])
{
if(dis[ver[i]]>dis[tmp]+quan[i]&&f[i])
{
dis[ver[i]]=dis[tmp]+quan[i];
with[ver[i]]=i;mn[ver[i]]=min(f[i],mn[tmp]);
if(!in[ver[i]])in[ver[i]]=1,q.push(ver[i]);
}
}
}
return dis[T]!=inf;
}
int zeng()
{
for(int i=T;i;i=ver[with[i]^1])
{
f[with[i]]-=mn[T];f[with[i]^1]+=mn[T];
}
return mn[T]*dis[T];
}
int main()
{
scanf("%d%d",&n,&m);
S=0;T=n+2;
tot=1;
int tmp;
for(int i=1;i<=n;i++)
{
scanf("%d",&tmp);
add(i,T,tmp,0);
add(S,i+1,tmp,0);
add(i,i+1,inf,0);
}
int t1,t2,t3;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&t1,&t2,&t3);
add(t2+1,t1,inf,t3);
}
int ans=0;
while(tell())ans+=zeng();
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: