日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Trie】【费用流】管道监控(loj 3026)

發(fā)布時(shí)間:2023/12/3 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Trie】【费用流】管道监控(loj 3026) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

正題

loj 3026


題目大意

給你一棵樹,和若干匹配串,如果一個(gè)節(jié)點(diǎn)向下的某條鏈構(gòu)成了匹配串i,則可以花費(fèi)這w_i匹配這條鏈,問你匹配完所有點(diǎn)的最小代價(jià)


解題思路

這題可以理解為樹上樹上的線性規(guī)劃

先對于每個(gè)匹配串倒著建trie,然后每個(gè)點(diǎn)向父親跑trie,當(dāng)跑到一個(gè)匹配串時(shí),就連接頭和尾,費(fèi)用為wiw_iwi?,流量inf

然后每個(gè)點(diǎn)向子節(jié)點(diǎn)連流量inf費(fèi)用0的邊

s向葉子節(jié)點(diǎn)連流量1費(fèi)用0的邊,如果一個(gè)點(diǎn)的子節(jié)點(diǎn)大于1就把多余的流到t,1要把所有流量流到t

就在樹上找到匹配串,然后就是經(jīng)典的線性規(guī)劃


代碼

#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define N 510 #define M 1000100 using namespace std; ll n, m, T, x, s, t, w, tot, ans, sum, summ; ll h[N], f[N], b[N], fr[N], fa[N], deg[N], v[M], wh[M], to[M][26]; char cl[N], st[M]; bool p[N]; queue<ll>d; const ll inf = 1e15; struct rec {ll to, next, f, w, c; }e[N*N<<2]; void add(ll x, ll y, ll f, ll c, ll w) {e[++tot].to = y;e[tot].f = f;e[tot].w = w;//編號e[tot].c = c;e[tot].next = h[x];h[x] = tot;e[++tot].to = x;e[tot].f = 0;e[tot].w = 0;e[tot].c = -c;e[tot].next = h[y];h[y] = tot;return; } void insert(ll x, char* s, ll whi) {ll now = 0, len = strlen(s+1);for (ll i = len; i > 0; --i){ll y = s[i] - 97;if (!to[now][y]) to[now][y] = ++w;now = to[now][y];}if (!v[now] || x < v[now]){v[now] = x;wh[now] = whi;}return; } void dfs(ll x) {ll now = 0;for (ll i = x; i != 1; i = fa[i]){ll y = cl[i] - 97;if (!to[now][y]) break;now = to[now][y];if (v[now]) add(x, fa[i], inf, v[now], wh[now]);}return; } bool spfa() {memset(b, 127/3, sizeof(b));memset(f, 0, sizeof(f));memset(p, 0, sizeof(p));while(!d.empty()) d.pop();d.push(s);p[s] = 1;b[s] = 0;f[s] = inf;while(!d.empty()){ll u = d.front();d.pop();for (ll i = h[u]; i; i = e[i].next){ll v = e[i].to;if (b[u] + e[i].c < b[v] && e[i].f){fr[v] = i;b[v] = b[u] + e[i].c;f[v] = min(f[u], e[i].f);if (!p[v]){p[v] = 1;d.push(v);}}}p[u] = 0;}return f[t]; } void dfs() {ll now = t;while(fr[now]){e[fr[now]].f -= f[t];e[fr[now]^1].f += f[t];now = e[fr[now]^1].to;}ans += f[t] * b[t];sum += f[t];return; } int main() {scanf("%lld%lld%lld", &n, &m, &T);tot = 1;for (ll i = 2; i <= n; ++i){scanf("%lld", &x);fa[i] = x;add(x, i, inf, 0, 0);deg[x]++; cl[i] = getchar();while(cl[i] < 'a' || 'z' < cl[i]) cl[i] = getchar();}s = n + 1;t = n + 2;for (ll i = 1; i <= m; ++i){scanf("%lld%s", &x, st+1);insert(x, st, i);}for (ll i = 2; i <= n; ++i){dfs(i);if (!deg[i]) add(s, i, 1, 0, 0);else if (deg[i] > 1){add(i, t, deg[i] - 1, 0, 0);//多的流掉summ += deg[i] - 1;//計(jì)算理論總流量}}add(1, t, deg[1], 0, 0);summ += deg[1];while(spfa())dfs();if (sum < summ)//有的邊到不了{puts("-1");return 0;}printf("%lld\n", ans);if (T){ans = 0;for (ll i = 2; i <= n; ++i)for (ll j = h[i]; j; j = e[j].next)if (e[j].w && e[j].f < inf)//輸出方案ans++;printf("%lld\n", ans);for (ll i = 2; i <= n; ++i)for (ll j = h[i]; j; j = e[j].next)if (e[j].w && e[j].f < inf)printf("%lld %lld %lld\n", e[j].to, i, e[j].w);}return 0; }

總結(jié)

以上是生活随笔為你收集整理的【Trie】【费用流】管道监控(loj 3026)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。