1. 程式人生 > >線性規劃費用流解法(Bzoj1061: [Noi2008]誌願者招募)

線性規劃費用流解法(Bzoj1061: [Noi2008]誌願者招募)

UC ++ 求解 oid const mem IV memset cpp

題面

傳送門

Sol

線性規劃費用流解法用與求解未知數為非負數的問題

這道題可以列出一堆形如
\(x[i]+x[j]+x[k]+...>=a[p]\)
的不等式
我們強行給每個式子減去一個東西,使他變成這樣
\(x[i]+x[j]+x[k]+...-y[p]==a[p]\)

然後相鄰兩個式子差分一下
把每個式子看成一個點
那麽這樣後,在這個題中所有的未知數只會出現在一個方程中
等式左邊符號是正的向符號為負的方程連邊,費用為代價,如果是補的未知數\(y\),那麽費用為零
右邊的數是正的連\(s\),否則連\(t\)
費用流出解

# include <bits/stdc++.h>
# define IL inline
# define RG register # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'
; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } const int maxn(1005); const int inf(1e9); int n, m, first[maxn], cnt, ans, s, t; int dis[maxn], pre1[maxn], pre2[maxn], vis[maxn]; queue <int> q; struct Edge{ int to, next, f, w; } edge[maxn * 25]; IL void
Add(RG int u, RG int v, RG int f, RG int w){ edge[cnt] = (Edge){v, first[u], f, w}, first[u] = cnt++; edge[cnt] = (Edge){u, first[v], 0, -w}, first[v] = cnt++; } IL int Aug(){ for(RG int i = s; i <= t; ++i) dis[i] = inf; q.push(s), dis[s] = 0, vis[s] = 1; while(!q.empty()){ RG int u = q.front(); q.pop(); for(RG int e = first[u]; e != -1; e = edge[e].next){ RG int v = edge[e].to; if(edge[e].f && dis[v] > dis[u] + edge[e].w){ dis[v] = dis[u] + edge[e].w; pre1[v] = e, pre2[v] = u; if(!vis[v]) q.push(v), vis[v] = 1; } } vis[u] = 0; } if(dis[t] == inf) return 0; RG int ret = inf; for(RG int p = t; p; p = pre2[p]) ret = min(ret, edge[pre1[p]].f); ans += ret * dis[t]; for(RG int p = t; p; p = pre2[p]) edge[pre1[p]].f -= ret, edge[pre1[p] ^ 1].f += ret; return 1; } int main(){ n = Input(), m = Input(); s = 0, t = n + 2; for(RG int i = s; i <= t; ++i) first[i] = -1; RG int last = 0; for(RG int i = 1; i <= n; ++i){ RG int v = Input(); if(v - last > 0) Add(s, i, v - last, 0); else if(v - last < 0) Add(i, t, last - v, 0); last = v, Add(i + 1, i, inf, 0); } Add(n + 1, t, last, 0); for(RG int i = 1; i <= m; ++i){ RG int l = Input(), r = Input(), c = Input(); Add(l, r + 1, inf, c); } while(Aug()); printf("%d\n", ans); return 0; }

線性規劃費用流解法(Bzoj1061: [Noi2008]誌願者招募)