题意:
给出一个有向图,每次可以删除存在入度的点及其出边,每次删除一个点可以获得其权值。
问最终能够获得的最大权值为多少。
思路:
考虑DAG:我们直接倒着拓扑序来选,即可将所有入度不为\(0\)的点选完。
若不为DAG,考虑\(tarjan\)求出强连通分量,分析可以发现:对于一个单独的强连通分量,假设其点数为\(n\),那么可以选择\(n-1\)个点;若其入度不为\(0\),那么强连通分量中所有点都可以选择。
然后直接这样来搞就行。
证明...我也不会,在纸上画画就行了。
#include <bits/stdc++.h> #define MP make_pair #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() #define INF 0x3f3f3f3f // #define Local #ifdef Local #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0) void err() { std::cout << '\n'; } template<typename T, typename...Args> void err(T a, Args...args) { std::cout << a << ' '; err(args...); } #else #define dbg(...) #endif void pt() {std::cout << '\n'; } template<typename T, typename...Args> void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); } using namespace std; typedef long long ll; typedef pair<int, int> pii; //head const int N = 5e5 + 5, M = 2e6 + 5; struct Edge{ int v, next; }e[M]; int a[N]; int head[N], tot; void adde(int u, int v) { e[tot].v = v; e[tot].next = head[u]; head[u] = tot++; } int n, m, k; pii E[M]; stack <int> s; int T, num; int col[N], dfn[N], low[N], Min[N]; bool chk[N]; void Tarjan(int u){ dfn[u] = low[u] = ++T; s.push(u); for(int i = head[u]; i != -1;i = e[i].next){ int v = e[i].v; if(!dfn[v]){ Tarjan(v); low[u] = min(low[u], low[v]); }else if(!col[v]){ low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]){ num++; int now; do{ now = s.top(); s.pop(); col[now] = num; Min[num] = min(Min[num], a[now]); }while(!s.empty() && now!=u); } } int in[N]; void run() { cin >> n >> m >> k; memset(head, -1, sizeof(head)); tot = 0; memset(Min, INF, sizeof(Min)); ll ans = 0; for(int i = 1; i <= n; i++) cin >> a[i]; for(int i = 1; i <= m; i++) { int u, v; cin >> u >> v; E[i] = MP(u, v); adde(u, v); } for(int i = 1; i <= n; i++) { if(!dfn[i]) Tarjan(i); } for(int i = 1; i <= m; i++) { int u = E[i].fi, v = E[i].se; if(col[u] != col[v]) ++in[col[v]]; } for(int i = 1; i <= n; i++) { int bel = col[i]; if(a[i] == Min[bel] && in[bel] == 0) { if(!chk[bel]) { chk[bel] = 1; a[i] = 0; } } } sort(a + 1, a + n + 1); reverse(a + 1, a + n + 1); for(int i = 1; i <= k; i++) ans += a[i]; pt(ans); } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cout << fixed << setprecision(20); #ifdef Local freopen("../input.in", "r", stdin); freopen("../output.out", "w", stdout); #endif run(); return 0; }
来源:https://www.cnblogs.com/heyuhhh/p/11717068.html