bzoj3876 [Ahoi2014]支线剧情
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3876
【题解】
一眼看过去好像就是一个网络流啊
那怎么建图呢
首先图上的边看作下界为1,上界inf的边,费用为给定的费用。
每个点都可以回到起点(1)开始下一次的观看,所以每个点到1连下界为0,上界inf的边,费用为0.
这是一个“无源汇,有上下界,最小费用可行流”问题。
我们先按照有上下界的处理方法,将每条边上下界统一成上界,然后S连到入度为正,入度为负连到T,费用均为0,流量为度数绝对值。
这样我们建造的网络就可以得出每条边都选了下界时,还需要选择多少能够满足条件。
那么把每条边下界乘费用加进去即可。
注意一定要把S->x和x->T的整合一起连。
看了一眼以前某学长没整合跑了9s,我整合完跑了100ms..
# include <queue> # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 3e5 + 10; const int mod = 1e9+7; # define RG register # define ST static int n; int S, T, d[M]; int head[M], nxt[M], to[M], flow[M], w[M], tot=1; inline void add(int u, int v, int fl, int _w) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; flow[tot] = fl; w[tot] = _w; } inline void adde(int u, int v, int fl, int _w) { // printf("%d->%d, %d, cost = %d\n", u, v, fl, _w); add(u, v, fl, _w); add(v, u, 0, -_w); } namespace MCF { queue<int> q; int dis[M], pre[M]; bool vis[M]; inline bool spfa() { while(!q.empty()) q.pop(); for (int i=1; i<=n+2; ++i) vis[i] = 0, dis[i] = 1e9, pre[i] = 0; q.push(S); vis[S] = 1; dis[S] = 0; while(!q.empty()) { int top = q.front(); q.pop(); vis[top] = 0; for (int i=head[top]; i; i=nxt[i]) { if(flow[i] && dis[to[i]] > dis[top] + w[i]) { dis[to[i]] = dis[top] + w[i]; pre[to[i]] = i; if(!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } } // for (int i=1; i<=n+2; ++i) cout << i << ' ' << d[i] << endl; // puts(""); return dis[T] != 1e9; } inline int mcf() { int fl = 1e9, ans = 0; for (int i=pre[T]; i; i=pre[to[i^1]]) fl = min(fl, flow[i]); for (int i=pre[T]; i; i=pre[to[i^1]]) { flow[i] -= fl; flow[i^1] += fl; ans += fl * w[i]; } return ans; } inline int main() { int ret = 0; while(spfa()) ret += mcf(); return ret; } } int main() { int ans = 0; cin >> n; S = n+1, T = n+2; for (int i=1, m, Bi, Ti; i<=n; ++i) { scanf("%d", &m); for (int j=1; j<=m; ++j) { scanf("%d%d", &Bi, &Ti); adde(i, Bi, 1e9, Ti); d[Bi] ++; d[i] --; ans += Ti; } if(i != 1) adde(i, 1, 1e9, 0); } for (int i=1; i<=n; ++i) { if(d[i] > 0) adde(S, i, d[i], 0); if(d[i] < 0) adde(i, T, -d[i], 0); } cout << MCF::main() + ans << endl; return 0; }