hdu 5325 Crazy Bobo 拓扑排序

来源:互联网 发布:ant 打包java指定目录 编辑:程序博客网 时间:2024/05/16 15:13

题意:

给你一棵树,每个节点上都有一个权值。

让你找到一个连通的节点集合,使得根据节点权值升序排序后,第i个节点到第i+1个节点所经过的其它节点权值都小于第i个节点的权值。

问你这样的集合最大的size。


思路:

比较朴素的思路:枚举以每个节点作为根,进行dfs搜寻所有比父亲节点权值大的节点个数,复杂度n^2。如果我们开一个数组保存之前已经统计过的节点个数,则复杂度降为O(n)。

赛中我们队是dfs开栈交c++过的,但实际这并非正解。

后来问过出题人,杭电的栈虽小,但若可以使用开栈代码,则内存有多大就可以开多大。50万正常来说是承受不了的,普通正常赛事中栈深大概就26万。

正解:拓扑排序。根据输入建边,权值大的指向权值小的。


code1(拓扑排序、正解):

//#pragma comment(linker, "/STACK:1024000000,1024000000") #include <bits/stdc++.h>using namespace std;const int N = 5e5+5;typedef long long LL;int n;int w[N];int cnt[N];int ind[N];vector <int> edge[N];void solve() {    fill(cnt+1, cnt+n+1, 1);    queue <int> q;    for(int i = 1;i <= n; i++)        if(ind[i] == 0) q.push(i);    while(!q.empty()) {        int u = q.front(); q.pop();        for(auto &v:edge[u]) {            //if(w[i] < w[u]) continue;            cnt[v] += cnt[u];            if(--ind[v] == 0) q.push(v);        }    }    int res = 0;    for(int i = 1;i <= n; i++) res = max(res, cnt[i]);    printf("%d\n", res);}int main() {    while(scanf("%d", &n) != EOF) {        fill(edge+1, edge+n+1, vector <int>());        fill(ind+1, ind+n+1, 0);        for(int i = 1;i <= n; i++) scanf("%d", &w[i]);        for(int i = 1;i <= n-1; i++) {            int u, v;            scanf("%d%d", &u, &v);            if(w[u] < w[v]) swap(u, v);            edge[u].push_back(v);            ind[v]++;        }        solve();    }    return 0;}


code2(dfs、非正解):

#include <cstdio>#include <cstring>#include <iostream>#include <cstdlib>#include <algorithm>#include <vector>#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std;const int N = 5e5+5;typedef long long LL;int n;int a[N];int cnt[N];bool vis[N];vector <int> edge[N];int dfs(int u, int p) {    int ret = 0;    vis[u] = true;    for(auto &v : edge[u]) {        if(v == p) continue;        if(a[v] < a[u]) continue;        if(vis[v]) ret += cnt[v];        else ret += dfs(v, u);    }    cnt[u] = ret+1;    return ret+1;}void solve() {    int res = 0;    for(int i = 1;i <= n; i++){        if(vis[i]) res = max(res, cnt[i]);        else res = max(res, dfs(i, -1));    }    printf("%d\n", res);}    int main() {    while(scanf("%d", &n) != EOF) {        for(int i = 1;i <= n; i++){            edge[i].clear();            vis[i] = false;            cnt[i] = 0;        }        for(int i = 1;i <= n; i++) scanf("%d", &a[i]);        for(int i = 1;i <= n-1; i++) {            int u, v;            scanf("%d%d", &u, &v);            edge[u].push_back(v);            edge[v].push_back(u);        }        solve();    }    return 0;}




0 0