【费用流】[BZOJ1061]/[HYSBZ1061]志愿者招募
题目
分析:建图的方法还是比较难想。
首先,计算两个相邻时刻的差分,若a[i] < a[i-1],就从i向汇点连边,容量为a[i-1]-a[i],若a[i] > a[i-1],就从源点向i连边,容量为a[i]-a[i-1]
请联系差分数组理解。
然后,对于志愿者,连s->(t+1),容量为+∞,费用为c。
最后,由于志愿者可以多不能少,连(i+1)->i,容量为+∞。
跑费用流算出费用即可。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define MAXN 1000
#define MAXM 10000
#define INF 0x7f7f7f7f7f7f7f7fll
using namespace std;
deque<int>q;
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
int n,m,S,T,a[MAXN+10];
typedef long long LL;
LL dist[MAXN+10],cost;
bool vis[MAXN+10];
struct node{
int wt,v;
LL cap;
node *next,*back;
}*adj[MAXN+10],edge[MAXN*4+MAXM*2+10],*ecnt=edge,*pre[MAXN+10];
template<class T>
void Read(T &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
void addedge(int u,int v,int wt,LL cap){
node *p=++ecnt;
p->v=v;
p->wt=wt;
p->cap=cap;
p->next=adj[u];
adj[u]=p;
p=p->back=++ecnt;
p->v=u;
p->wt=-wt;
p->cap=0;
p->next=adj[v];
adj[v]=p;
p->back=ecnt-1;
}
void read(){
Read(n),Read(m);
int i,s,t,c;
T=n+2;
for(i=1;i<=n;i++)
Read(a[i]);
for(i=1;i<=n;i++){
if(a[i]>a[i-1])
addedge(S,i,0,a[i]-a[i-1]);
else if(a[i]<a[i-1])
addedge(i,T,0,a[i-1]-a[i]);
addedge(i+1,i,0,INF);
}
addedge(n+1,T,0,a[n]);
for(i=1;i<=m;i++){
Read(s),Read(t),Read(c);
addedge(s,t+1,c,INF);
}
}
bool spfa(){
memset(dist,0x7f,sizeof dist);
memset(pre,0,sizeof pre);
q.push_back(S);
vis[S]=1;
dist[S]=0;
int u,v,len;
LL sum;
while(!q.empty()){
u=q.front();
q.pop_front();
if(dist[u]*len>sum){
q.push_back(u);
continue;
}
len--;
sum-=dist[u];
vis[u]=0;
for(node *p=adj[u];p;p=p->next){
v=p->v;
if(p->cap>0&&dist[v]>dist[u]+p->wt){
dist[v]=dist[u]+p->wt;
pre[v]=p;
if(!vis[v]){
vis[v]=1;
if(q.empty()||dist[v]>dist[q.front()])
q.push_back(v);
else
q.push_front(v);
sum+=dist[v];
len++;
}
}
}
}
if(dist[T]==INF)
return 0;
return 1;
}
void mcmf(){
int u;
LL delta;
while(spfa()){
delta=INF;
for(u=T;u!=S;u=pre[u]->back->v)
delta=min(delta,pre[u]->cap);
for(u=T;u!=S;u=pre[u]->back->v){
pre[u]->cap-=delta;
pre[u]->back->cap+=delta;
cost+=delta*pre[u]->wt;
}
}
}
int main()
{
read();
mcmf();
printf("%lld\n",cost);
}