zoukankan      html  css  js  c++  java
  • BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )

    WA了好多次...

    先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就是记忆化搜一下...重边就用set判一下

    -------------------------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #include<iostream>
    #include<cctype>
    #include<set>
     
    using namespace std;
     
    const int maxn = 100009;
    const int INF = 0x3F3F3F3F;
     
    inline int read() {
    char c = getchar();
    int ret = 0;
    for(; !isdigit(c); c = getchar());
    for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
    return ret;
    }
     
    struct edge {
    int to;
    edge* next;
    } E[1000009], *pt = E, *head[maxn];
     
    void addedge(int u, int v) {
    pt->to = v; pt->next = head[u]; head[u] = pt++;
    }
     
    int N, scc[maxn], dfn[maxn], low[maxn], tot[maxn], CK = 0, n = -1, MOD;
    stack<int> S;
    set<pair<int, int> > bst;
     
    void tarjan(int x) {
    dfn[x] = low[x] = ++CK;
    S.push(x);
    for(edge* e = head[x]; e; e = e->next)
    if(!dfn[e->to])
    tarjan(e->to), low[x] = min(low[e->to], low[x]);
    else if(!~scc[e->to])
    low[x] = min(low[x], dfn[e->to]);
    if(dfn[x] == low[x]) {
    int t; n++;
    do {
    t = S.top(); S.pop();
    tot[n]++;
    scc[t] = n;
    } while(t != x);
    }
    }
     
    namespace DP {
    edge E[1000009], *pt = E, *head[maxn];
    int dp[maxn], cnt[maxn];
    bool vis[maxn];
    void addedge(int u, int v) {
    pt->to = v; pt->next = head[u]; head[u] = pt++;
    }
    void init() {
    memset(dp, 0, sizeof dp);
    memset(cnt, 0, sizeof cnt);
    memset(vis, 0, sizeof vis);
    }
    void Dp(int x) {
    if(vis[x]) return;
    vis[x] = true;
    for(edge* e = head[x]; e; e = e->next) {
    Dp(e->to);
    if(dp[e->to] > dp[x])
    dp[x] = dp[e->to], cnt[x] = cnt[e->to];
    else if(dp[e->to] == dp[x] && (cnt[x] += cnt[e->to]) >= MOD) 
    cnt[x] -= MOD;
    }
    dp[x] += tot[x];
    if(!cnt[x]) cnt[x] = 1;
    }
    void work() {
    for(int i = 0; i <= n; i++) 
    if(!vis[i]) Dp(i);
    int ans = 0, ans0 = 0;
    for(int i = 0; i <= n; i++)
    if(dp[i] > ans) ans = dp[i], ans0 = cnt[i];
    else if(ans == dp[i] && (ans0 += cnt[i]) >= MOD) ans0 -= MOD;
    printf("%d %d ", ans, ans0);
    }
    }
     
    void AddEdge() {
    for(int x = 0; x < N; x++)
    for(edge* e = head[x]; e; e = e->next) 
    if(scc[x] != scc[e->to] && bst.find(make_pair(scc[x], scc[e->to])) == bst.end()) {
    DP::addedge(scc[x], scc[e->to]);
    bst.insert(make_pair(scc[x], scc[e->to]));
    }
    }
     
    void TARJAN() {
    memset(dfn, 0, sizeof dfn);
    memset(low, 0, sizeof low);
    memset(scc, -1, sizeof scc);
    memset(tot, 0, sizeof tot);
    for(int i = 0; i < N; i++) if(!dfn[i]) tarjan(i);
    }
     
    void init() {
    N = read();
    int m = read();
    MOD = read();
    while(m--) {
    int u = read() - 1, v = read() - 1;
    addedge(u, v);
    }
    DP::init();
    }
     
    int main() {
    init();
    TARJAN();
    DP::init();
    AddEdge();
    DP::work();
    return 0;
    }

    -------------------------------------------------------------------------------------------

    1093: [ZJOI2007]最大半连通子图

    Time Limit: 30 Sec  Memory Limit: 162 MB
    Submit: 2105  Solved: 841
    [Submit][Status][Discuss]

    Description

    Input

    第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。

    Output

    应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

    Sample Input

    6 6 20070603
    1 2
    2 1
    1 3
    2 4
    5 6
    6 4

    Sample Output

    3
    3

    HINT

    对于100%的数据, N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8。

    Source

  • 相关阅读:
    Java并发包源码学习系列:基于CAS非阻塞并发队列ConcurrentLinkedQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之LinkedBlockingDeque源码解析
    Java并发包源码学习系列:阻塞队列实现之LinkedTransferQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之SynchronousQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之PriorityBlockingQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之LinkedBlockingQueue源码解析
    Java并发包源码学习系列:阻塞队列实现之ArrayBlockingQueue源码解析
    Java并发包源码学习系列:阻塞队列BlockingQueue及实现原理分析
    Java并发包源码学习系列:JDK1.8的ConcurrentHashMap源码解析
    Java并发包源码学习系列:挂起与唤醒线程LockSupport工具类
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4875587.html
Copyright © 2011-2022 走看看