看了报告才写出来的.
添加一个汇点,把所有非源点城市添加一条边到汇点,容量为无穷大,代价为负的该城市的单价(巧妙的转换).
然后就是无向图的最小费用最大流问题了,最后把答案取反.
#include <iostream>
#include <queue>
#include <cstdio>
#define INF 0X20202020
using namespace std;
const int maxn = 110;
struct edge{
int u, v, cap, cost, next;
}es[maxn * maxn];
int head[maxn], fa[maxn], idx[maxn], inq[maxn], dis[maxn], n, m;
void addEdge(int u, int v, int cap, int cost, int & eidx){
es[eidx].u = u;
es[eidx].v = v;
es[eidx].cap = cap;
es[eidx].cost = cost;
es[eidx].next = head[u];
head[u] = eidx ++;
es[eidx].u = v;
es[eidx].v = u;
es[eidx].cap = 0;
es[eidx].cost = -cost;
es[eidx].next = head[v];
head[v] = eidx ++;
}
void spfa(int s, int e){
memset(dis, 0X20, sizeof(dis));
memset(inq, 0, sizeof(inq));
memset(fa, -1, sizeof(fa));
memset(idx, -1, sizeof(idx));
queue<int> q;
q.push(s);
inq[s] = 1;
dis[s] = 0;
while (q.size()){
int u = q.front();q.pop();
inq[u] = 0;
for (int ne = head[u]; ne != -1; ne = es[ne].next){
int v = es[ne].v, w = es[ne].cost;
if (es[ne].cap && dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
fa[v] = u;
idx[v] = ne;
if(!inq[v]){
inq[v] = 1;
q.push(v);
}
}
}
}
}
int minCostMaxFlow(int s, int e){
int ans = 0;
while (1){
spfa(s, e);
if(dis[e] >= 0)break;
int minv = INF;
for (int i = e; idx[i] != -1; i = fa[i]){
int ei = idx[i];
if(es[ei].cap < minv){
minv = es[ei].cap;
}
}
for (int i = e; idx[i] != -1; i = fa[i]){
es[idx[i]].cap -= minv;
es[idx[i] ^ 1].cap += minv;
}
ans += dis[e] * minv;
}
return -ans;
}
int main(){
while (scanf("%d%d", &n, &m) == 2){
memset(head, -1, sizeof(head));
int eidx = 0;
for (int i = 2; i <= n; ++i ){
int p;
scanf("%d", &p);
addEdge(i, n + 1, INF, -p, eidx);
}
for (int i = 0; i < m; ++i){
int u, v, w, c;
scanf("%d %d %d %d", &u, &v, &w, &c);
addEdge(u, v, w, c, eidx);
addEdge(v, u, w, c, eidx);
}
printf("%d\n",minCostMaxFlow(1, n + 1));
}
return 0;
}