题意:
你有n个课程 每个课程有一个规定的毕业学分 修学分有m种方式 每种方式要求先修到x课程x'学分以上才能花费money去修y课程并且将学分修到y' 问 最少花费多少可以毕业
思路:
一开始想费用流 建完图发现一个问题解决不掉 那就是 一条边如果流过多次怎样才能让费用只计算一次 所以换思路
我们知道 为了应付“ 学分修到y' ”这个条件 高层学分一定要“覆盖”低层学分 那么就想到以每个学分为一个点 高层向低层连边 费用为0 同时修学分的方式是输入的 直接建边 费用为输入费用 一开始只能走到0学分 所以超级源点向所有0学分连边 费用0 那么此时我们想要的是从源点花最小费用走到所有点 这就是有向图最小生成树 即最小树形图
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define M 610
#define inf 2000000000
int n, m, ans, tot, S;
int head[M], id[M], in[M], pre[M], vis[M], node[M][M], s[M];
struct ed {
int u, v, w, next;
} ed[M * M];
int ZL(int root, int V, int E) {
int ret = 0;
for (;;) {
for (int i = 0; i < V; i++) {
id[i] = -1;
vis[i] = -1;
in[i] = inf;
}
for (int i = 0; i < E; i++) {
int u = ed[i].u;
int v = ed[i].v;
if (ed[i].w < in[v] && u != v) {
pre[v] = u;
in[v] = ed[i].w;
}
}
for (int i = 0; i < V; i++) {
if (i == root)
continue;
if (in[i] == inf)
return -1;
}
int cnt = 0;
in[root] = 0;
for (int i = 0; i < V; i++) {
ret += in[i];
int v = i;
while (vis[v] != i && id[v] == -1 && v != root) {
vis[v] = i;
v = pre[v];
}
if (v != root && id[v] == -1) {
for (int u = pre[v]; u != v; u = pre[u])
id[u] = cnt;
id[v] = cnt++;
}
}
if (cnt == 0)
break;
for (int i = 0; i < V; i++)
if (id[i] == -1)
id[i] = cnt++;
for (int i = 0; i < E; i++) {
int u = ed[i].u;
int v = ed[i].v;
ed[i].u = id[u];
ed[i].v = id[v];
if (id[u] != id[v])
ed[i].w -= in[v];
}
V = cnt;
root = id[root];
}
return ret;
}
void add(int U, int V, int W) {
ed[tot].u = U;
ed[tot].v = V;
ed[tot].w = W;
ed[tot].next = head[U];
head[U] = tot++;
}
int main() {
int i, j, k, u, v, tmp;
while (scanf("%d%d", &n, &m) != EOF) {
if (!n && !m)
break;
k = 0;
for (i = 1; i <= n; i++) {
scanf("%d", &s[i]);
for (j = 0; j <= s[i]; j++)
node[i][j] = k++;
}
S = k++;
tot = 0;
memset(head, -1, sizeof(head));
for (i = 1; i <= n; i++) {
add(S, node[i][0], 0);
for (j = 1; j <= s[i]; j++)
add(node[i][j], node[i][j - 1], 0);
}
for (i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
tmp = node[u][v];
scanf("%d%d", &u, &v);
v = node[u][v];
u = tmp;
scanf("%d", &tmp);
add(u, v, tmp);
}
ans = ZL(S, k, tot);
printf("%d\n", ans);
}
return 0;
}