链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1061
题解
1A系列。
具体参考姜志豪《网络流的一些建模方法》
随便列一些方程然后减一下,然后就得到n+1个方程。一个方程总是”……=0”,变量就是流,所以必须规定其非负,每个式子都是点,一个变量在这个式子中的系数是负数,就说明这个流从这个点流出,否则说明流入。有个地方论文中说的不够详细,就是化简之后,X[i]这个的整数项存在于第s[i]个式子中,而负数项存在于第t[i]+1个式子中。(因为中间的都抵消了)
代码
//费用流
#include <cstdio>
#include <algorithm>
#include <queue>
#define maxn 500000
#define inf ((long long)1<<60)
#define ll long long
using namespace std;
ll N, M, need[maxn], s[maxn], t[maxn], in[maxn], to[maxn], head[maxn], tot=1, w[maxn],
c[maxn], nex[maxn], S, T, dist[maxn], pre[maxn], cost, v[maxn];
queue<ll> q;
ll read(ll x=0)
{
char c=getchar();
while(c<48 or c>57)c=getchar();
while(c>=48 and c<=57)x=x*10+c-48,c=getchar();
return x;
}
void adde(ll a, ll b, ll cc, ll ww)
{to[++tot]=b;c[tot]=cc;w[tot]=ww;nex[tot]=head[a];head[a]=tot;}
void adde2(ll a, ll b, ll cc, ll ww){adde(a,b,cc,ww);adde(b,a,0,-ww);}
bool spfa()
{
ll x, p, i;
for(i=1;i<=T;i++)dist[i]=inf;
in[S]=1;q.push(S);dist[S]=0;
while(!q.empty())
{
in[x=q.front()]=0;q.pop();
for(p=head[x];p;p=nex[p])
{
if(c[p] and dist[to[p]]>dist[x]+w[p])
{
pre[to[p]]=p;
dist[to[p]]=dist[x]+w[p];
if(!in[to[p]])in[to[p]]=1,q.push(to[p]);
}
}
}
return dist[T]!=inf;
}
void augment()
{
ll x, flow=inf;
for(x=T;x^S;x=to[pre[x] xor 1])flow=min(flow,c[pre[x]]);
for(x=T;x^S;x=to[pre[x] xor 1])c[pre[x]]-=flow, c[pre[x] xor 1]+=flow;
cost+=dist[T]*flow;
}
void init()
{
ll i, tmp;
N=read(), M=read();
for(i=1;i<=N;i++)need[i]=read();
for(i=1;i<=M;i++)s[i]=read(),t[i]=read(),v[i]=read();
S=N+10, T=S+1;
for(i=1;i<=N+1;i++)
{
tmp=need[i-1]-need[i];
if(tmp>0)adde2(S,i,tmp,0);
else adde2(i,T,-tmp,0);
if(i>1)adde2(i-1,i,inf,0);
}
for(i=1;i<=M;i++)adde2(t[i]+1,s[i],inf,v[i]);
}
int main()
{
init();
while(spfa())augment();
printf("%lld",cost);
return 0;
}