题意:
你有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; }