【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1061
【题解】
如果一个线性规划问题的每个变量只在两个限制条件中出现过,并且一个是正的,一个是负的,那么就可以把这个问题转换为网络流模型,每个限制条件建一个点,每个变量从负的往正的连边,正的常量从原点连过来,负的常量连向汇点。由于每个限制条件的点都满足流量平衡,所以这个正确的。
现在考虑如何转换。对于:
X≥A
X
≥
A
的条件。我们添加辅助变量
Q
Q
使方程变为:
然后把方程做差,即后一个方程减去前一个方程。那么就转换成网络流模型。
对于第
i
i
种志愿者,在第个方程中会有一个正的,在第
Ti+1
T
i
+
1
个会有一个负的。
Q
Q
<script type="math/tex" id="MathJax-Element-7">Q</script>总是从后一个向前一个连边。
/* --------------
user Vanisher
problem bzoj-1061
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 1010
# define M 50010
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
struct node{
int data,next,l,vote,re;
}e[M];
int place,head[N],dis[N],use[N],can[N],ned[N],frm[N],n,m,S,T,q[N];
ll ans;
void build(int u, int v, int l, int w){
e[++place].data=v; e[place].next=head[u]; head[u]=place; e[place].vote=w; e[place].l=l; e[place].re=place+1;
e[++place].data=u; e[place].next=head[v]; head[v]=place; e[place].vote=-w; e[place].l=0; e[place].re=place-1;
}
void spfa(){
memset(dis,inf,sizeof(dis));
memset(use,0,sizeof(use));
dis[S]=0; use[S]=1; can[S]=inf;
int pl=1, pr=1; q[1]=S;
while (pl<=pr){
int x=q[(pl++)%N];
for (int ed=head[x]; ed!=0; ed=e[ed].next)
if (dis[e[ed].data]>dis[x]+e[ed].vote&&e[ed].l!=0){
dis[e[ed].data]=dis[x]+e[ed].vote;
can[e[ed].data]=min(e[ed].l,can[x]);
frm[e[ed].data]=ed;
if (use[e[ed].data]==0){
use[e[ed].data]=1;
q[(++pr)%N]=e[ed].data;
}
}
use[x]=0;
}
}
void change(){
ans=ans+(long long)dis[T]*(long long)can[T];
int now=T;
while (now!=S){
e[frm[now]].l-=can[T];
e[e[frm[now]].re].l+=can[T];
now=e[e[frm[now]].re].data;
}
}
void flow(){
for (spfa(); dis[T]!=inf; spfa())
change();
}
int main(){
n=read(), m=read();
S=0; T=n+2;
for (int i=1; i<=n; i++)
scanf("%d",&ned[i]);
for (int i=1; i<=n+1; i++){
if (ned[i]-ned[i-1]>=0)
build(S,i,ned[i]-ned[i-1],0);
else build(i,T,ned[i-1]-ned[i],0);
if (i!=1) build(i,i-1,inf,0);
}
for (int i=1; i<=m; i++){
int s=read(), t=read(), c=read();
build(s,t+1,inf,c);
}
flow();
printf("%lld\n",ans);
return 0;
}