【费用流】loj_3026「ROIR 2018 Day1」管道监控
题意
给出一棵树,每条连边有一个字母。
给出若干个规范,使用有耗费。
用若干规范去覆盖这颗树使得每条边至少被覆盖一遍,求最小耗费及覆盖方案。
思路
利用网络流处理覆盖问题。
对于树上的一个子串,如果可以用规范覆盖(利用trie判断),那么在头尾之间连接一条边表示覆盖。
对于两个规范之间有重叠,从父节点向子节点连边,即退回再流上去。
对于一个点有多个流量,将它流出去(具体地,最多有儿子个数的路径会流上来,所以流出去的流量最多是儿子个数-1)。
最后从S连向叶子节点,根节点1连向T。
跑最大流,若能跑满,即有解;输出方案即判断每条边是否有流量。
代码
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
struct node {
int a, b, c;
};
const int inf = 2147483647;
int to[1000001][26], w[1000001], k[1000001];
int n, m, t, cnt, scnt, S, T, ans, ansf, tot = 1;
int fa[1000001], son[1000001];
int v[260001], d[260001], pre[260001], head[260001], ver[520001], next[520001], flow[520001], cost[520001], mode[520001];
std::vector<node> anss;
char c[501], s[1000001];
void insert(char *s, int l, int ww, int mm) {
int p = 0;
for (int i = l - 1; i >= 0; i--) {
int ch = s[i] - 'a';
if (!to[p][ch]) to[p][ch] = ++cnt;
p = to[p][ch];
}
if (!w[p])
w[p] = ww, k[p] = mm;
else if (w[p] > ww) {
w[p] = ww;
k[p] = mm;
}
}
int spfa() {
std::queue<int> q;
for (int i = 1; i <= T; i++)
d[i] = 1e14 + 1;
memset(v, 0, sizeof(v));
memset(pre, 0, sizeof(pre));
d[S] = 0;
v[S] = 1;
q.push(S);
while (q.size()) {
int u = q.front();
q.pop();
v[u] = 0;
for (int i = head[u]; i; i = next[i]) {
if (!flow[i]) continue;
if (d[ver[i]] > d[u] + cost[i]) {
d[ver[i]] = d[u] + cost[i];
pre[ver[i]] = i;
if (!v[ver[i]]) {
q.push(ver[i]);
v[ver[i]] = 1;
}
}
}
}
return d[T] <= 1e14;//???
}
void addflow() {
int i = T, mn = 2147483647;
while (pre[i]) {
mn = std::min(mn, flow[pre[i]]);
i = ver[pre[i] ^ 1];
}
ans += mn * d[T];
ansf += mn;
i = T;
while (pre[i]) {
flow[pre[i]] -= mn;
flow[pre[i] ^ 1] += mn;
i = ver[pre[i] ^ 1];
}
}
void add(int u, int v, int f, int c) {
ver[++tot] = v, next[tot] = head[u], flow[tot] = f, cost[tot] = c, head[u] = tot;
ver[++tot] = u, next[tot] = head[v], flow[tot] = 0, cost[tot] = -c, head[v] = tot;
}
signed main() {
scanf("%lld %lld %lld", &n, &m, &t);
for (int i = 2; i <= n; i++)
scanf("%lld %c", &fa[i], &c[i]), son[fa[i]]++;
for (int i = 1, x; i <= m; i++) {
scanf("%lld ", &x);
scanf("%s", s);
insert(s, strlen(s), x, i);
}
S = n + 1, T = n + 2;
for (int i = 2; i <= n; i++) {
for (int x = i, p = 0; x != 1; x = fa[x]) {
int ch = c[x] - 'a';
if (!to[p][ch])
break;
p = to[p][ch];
if (w[p])
add(i, fa[x], inf, w[p]), mode[tot - 1] = k[p];
}
add(fa[i], i, inf, 0);
if (son[i] >= 2)
add(i, T, son[i] - 1, 0);
if (!son[i])
add(S, i, 1, 0), scnt++;
}
add(1, T, son[1], 0);
while (spfa())
addflow();
if (ansf != scnt)
return !printf("-1");
printf("%lld", ans);
if (t) {
for (int i = 2; i <= tot; i++)
if (mode[i] && flow[i ^ 1])
anss.push_back((node){ver[i], ver[i ^ 1], mode[i]});
printf("\n%lld\n", anss.size());
for (int i = 0; i != anss.size(); i++)
printf("%lld %lld %lld\n", anss[i].a, anss[i].b, anss[i].c);
}
}
坑
输出完\(-1\)没有退出程序
没有考虑到最短路的最大值

浙公网安备 33010602011771号