P5008 [yLOI2018] 锦鲤抄(Tarjan+贪心)

洛谷

题意:
给出一个有向图,每次可以删除存在入度的点及其出边,每次删除一个点可以获得其权值。
问最终能够获得的最大权值为多少。

思路:
考虑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 << '
'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '
'; }
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