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

时光总嘲笑我的痴心妄想 提交于 2020-03-10 08:20:55

洛谷

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

思路:
考虑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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!