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\n", ans);
    }
    return 0;
} 

 

posted @ 2017-11-02 09:48  yohanlong  阅读(99)  评论(0编辑  收藏  举报