• uva11324


    真正意义上由自己思维推断出的第一题。

    实际上思路也和正解一致。

    题意是给你一个有向图,让你求一个点集,使得点集中任意一对点对(u,v),要么u可以到v,要么v可以到u。

    我们可以发现,对于一个SCC而言,要么都选,要么都不选(换句话说,如果我们选中了SCC中的任意一点,那么也可以顺便把SCC中的其他点也顺便选上)

    这样我们先缩点,然后在新图上(每个点相当于一个SCC,并且点权为SCC的大小)跑DAG的最长路即可。

    这个用一个dp实现。

    设d[i]=以i为起点的最长路的长度。

    则d[i] = max{d[j] + val[j] | G[i][j] != 0}

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    
    using namespace std;
    
    const int maxn = 1005, maxm = 50005;
    
    stack<int> s;
    
    int t, n, m, tot, dfs_clock, scc_cnt;
    
    int h[maxn], dfn[maxn], low[maxn], sccno[maxn];
    
    int h2[maxn], d[maxn], vis[maxn], val[maxn];
    
    int tot2;
    
    struct edge
    {
        int v, next;
    }a[maxm], a2[maxm];
    
    void add(int x, int y)
    {
        a[tot].v = y;
        a[tot].next = h[x];
        h[x] = tot++;
    }
    
    void add2(int x, int y)
    {
        a2[tot2].v = y;
        a2[tot2].next = h2[x];
        h2[x] = tot2++;
    }
    
    int dfs(int u, int fa)
    {
        s.push(u);
        int lowu = dfn[u] = ++dfs_clock;
        for (int i = h[u]; ~i; i = a[i].next)
        {
            int v = a[i].v;
            if (!dfn[v])
            {
                int lowv = dfs(v, u);
                lowu = min(lowu, lowv);
            }
            else if (!sccno[v])
            {
                lowu= min(lowu, dfn[v]);
            }
        }
        if (lowu == dfn[u])
        {
            scc_cnt++;
            int scc_num = 0;
            for (;;)
            {
                scc_num++;
                int x = s.top(); s.pop();
                sccno[x] = scc_cnt;
                if (x == u) break;
            }
            val[sccno[u]] = scc_num;
        }
        return low[u] = lowu;
    }
    
    int dp(int u)
    {
        if (vis[u]) return d[u];
        vis[u] = 1;
        int& ans = d[u];
        ans = val[u];
        for (int i =h2[u]; ~i; i = a2[i].next)
        {
            int v = a2[i].v;
            ans = max(ans, dp(v) + val[u]);
        }
        return ans;
    }
    
    int main()
    {
    //    freopen("uva11324.in","r",stdin);
        scanf("%d", &t);
        while (t--)
        {
            scanf("%d%d", &n, &m);
            memset(h, -1, sizeof h); tot = dfs_clock = scc_cnt = 0;
            memset(dfn, 0, sizeof dfn);
            memset(low, 0, sizeof low);
            memset(sccno, 0, sizeof sccno);
            memset(val, 0, sizeof val);
            for (int i = 1; i <= m; i++)
            {
                int x, y;
                scanf("%d%d", &x, &y);
                add(x, y);
            }
            for (int i = 1; i <= n; i++)
                if (!dfn[i])
                    dfs(i, 0);
            memset(h2, -1, sizeof h2); tot2 = 0;
            for (int u = 1; u <= n; u++)
                for (int i = h[u]; ~i; i = a[i].next)
                {
                    int v = a[i].v;
                    if (sccno[u] != sccno[v])
                        add2(sccno[u], sccno[v]);
                }
            int ans = 0;
            memset(vis, 0, sizeof vis);
            memset(d, 0, sizeof d);
            for (int i = 1; i <= n; i++)
                ans = max(ans, dp(sccno[i]));
            printf("%d
    ", ans);
        }
        return 0;
    } 
  • 相关阅读:
    概要设计
    JNI内存泄露
    Flash 与 JS 交互
    Lucene.net 实现全文搜索(转)
    自动打开登录游戏的代码
    Ajax,网站改版的一种方法
    IE6/IE7和Firefox对Div处理的差异(转)
    搜VC里找到的
    C# 尝试读取或写入受保护的内存。这通常指示其他内存已损坏
    HTML特殊转义字符列表
  • 原文地址:https://www.cnblogs.com/yohanlong/p/7770798.html
Copyright © 2020-2023  润新知