题意:
给定一个带费用的流量网络,要求最大费用(不要求最大流)。
思路:
最小费用最大流魔改,将插入边的费用取反,此时每次进行增广会选一条最短的路径对答案产生贡献,开始这个路径是负的,但是之后为了满足最大流,贡献可能变成正的,因此只要对cost不断取min,最后的mincost就是答案的相反数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e3+5;
const ll INF=2e17;
typedef pair<ll,ll> pii;
struct MCMF {
struct Edge {
ll v, cap, cost, rev;
};
ll flow, cost, s, t, n,ans=INF;
ll dist[MAXN], H[MAXN], pv[MAXN], pe[MAXN];
std::vector<Edge> G[MAXN];
bool dijkstra() {
std::priority_queue<pii, std::vector<pii>, std::greater<pii> > q;
std::fill(dist, dist + n + 1, INF);
dist[s] = 0; q.push({0, s});
while (!q.empty()) {
pii x = q.top(); q.pop();
ll &u = x.second;
if (dist[u] < x.first) continue;
for (ll i = 0; i < G[u].size(); ++i) {
Edge &e = G[u][i];
ll &v = e.v;
pii y(dist[u] + e.cost + H[u] - H[v], v);
if (e.cap > 0 && dist[v] > y.first) {
dist[v] = y.first;
pe[v] = i, pv[v] = u;
q.push(y);
}
}
}
if (dist[t] == INF) return false;
for (ll i = 0; i <= n; ++i) H[i] += dist[i];
ll f = INF;
for (ll v = t; v != s; v = pv[v]) f = std::min(f, G[pv[v]][pe[v]].cap);
flow += f;
cost += f * H[t];
ans=min(ans,cost);
for (ll v = t; v != s; v = pv[v]) {
Edge &e = G[pv[v]][pe[v]];
e.cap -= f;
G[v][e.rev].cap += f;
}
return true;
}
void solve(ll s, ll t) {
this->s = s, this->t = t;
flow = cost = 0;
std::fill(H, H + n + 1, 0);
while (dijkstra());
}
void init(ll n) {
this->n = n;
for (ll i = 0; i <= n; ++i) G[i].clear();
}
void addEdge(ll u, ll v, ll cap, ll cost) {
G[u].push_back({v, cap, cost, G[v].size()});
G[v].push_back({u, 0, -cost, G[u].size() - 1});
}
} mcmf;
int a[MAXN];
int main () {
int n,m;
scanf("%d%d",&n,&m);
int s=n+1,t=n+2;
mcmf.init(n+2);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
mcmf.addEdge(u,v,c,-a[u]);
}
mcmf.addEdge(s,1,INF,0);
mcmf.addEdge(n,t,INF,-a[n]);
mcmf.solve(s,t);
printf("%lld
",-mcmf.ans);
}