主要思路
妈卖批,完全想偏了。刚开始思考的时候以为是要搞一颗有根的、根到叶子路径都满足递增。
后面发现其实这个图也有可能是个 DAG,而且树的话可能会因为 K 的限制没法搞。所以,我们就可以直接路径覆盖然后求最小费用即可。
代码
// P4542.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200, MAX_E = 1e6 + 200, INF = 0x3f3f3f3f; typedef long long ll; int n, m, k, current, head[MAX_N], pre[MAX_N], start_pos, end_pos, flow[MAX_N]; int mp[220][220]; ll dist[MAX_N]; bool vis[MAX_N]; struct edge { int to, nxt, weight, cost; } edges[MAX_E << 1]; void addpath(int src, int dst, int weight, int cost) { edges[current].to = dst, edges[current].nxt = head[src]; edges[current].weight = weight, edges[current].cost = cost; head[src] = current++; } void addtube(int src, int dst, int weight, int cost) { addpath(src, dst, weight, cost); addpath(dst, src, 0, -cost); } bool spfa() { queue<int> q; memset(dist, 0x3f, sizeof(dist)), memset(pre, -1, sizeof(pre)); memset(vis, false, sizeof(vis)), memset(flow, 0x3f, sizeof(flow)); q.push(start_pos), dist[start_pos] = 0, flow[start_pos] = INF; vis[start_pos] = true; while (!q.empty()) { int u = q.front(); q.pop(), vis[u] = false; for (int i = head[u]; i != -1; i = edges[i].nxt) if (edges[i].weight > 0 && dist[edges[i].to] > dist[u] + edges[i].cost) { dist[edges[i].to] = dist[u] + edges[i].cost, pre[edges[i].to] = i; flow[edges[i].to] = min(flow[u], edges[i].weight); if (!vis[edges[i].to]) q.push(edges[i].to), vis[edges[i].to] = true; } } return pre[end_pos] != -1; } int main() { memset(head, -1, sizeof(head)); memset(mp, 0x3f, sizeof(mp)); scanf("%d%d%d", &n, &m, &k), n++; start_pos = n + n + 1, end_pos = start_pos + 1; for (int i = 1; i <= n; i++) mp[i][i] = 0; for (int i = 1, u, v, e; i <= m; i++) { scanf("%d%d%d", &u, &v, &e); u++, v++, mp[u][v] = mp[v][u] = min(mp[u][v], e); } for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (k < max(i, j)) mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]); for (int i = 1; i <= n; i++) { addtube(start_pos, i, (i == 1) ? k : 1, 0); addtube(i + n, end_pos, 1, 0); for (int j = i + 1; j <= n; j++) if (mp[i][j] != INF) addtube(i, j + n, 1, mp[i][j]); } ll ret = 0; while (spfa()) { ret += 1LL * dist[end_pos] * flow[end_pos]; int u = end_pos; while (u != start_pos) { edges[pre[u]].weight -= flow[end_pos], edges[pre[u] ^ 1].weight += flow[end_pos]; u = edges[pre[u] ^ 1].to; } } printf("%lld\n", ret); return 0; }