tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows

缩点练习

洛谷 P3387 【模板】缩点

缩点

解题思路:

都说是模板了...先缩点把有环图转换成DAG
然后拓扑排序即可

#include <bits/stdc++.h>
using namespace std;
/*    freopen("k.in", "r", stdin);
    freopen("k.out", "w", stdout); */
//clock_t c1 = clock();
//std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef vector<int, int> VII;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 5e5 + 7;
const ll MAXM = 1e6 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
int head[MAXN], head1[MAXN];
int in[MAXN];
int n, m;
int vis[MAXN];
int dfn[MAXN], low[MAXN], dep;
int sta[MAXN], top = -1;
int tot; //强联通分量编号
int dis[MAXN];
int p[MAXN];
int num[MAXN];
struct Edge
{
    int u, v, Next;
    Edge(int _u = 0, int _v = 0, int _Next = 0) { u = _u, v = _v, Next = _Next; }
} e[MAXN << 1], ed[MAXN << 1];
int cnt = -1;
void add(int u, int v)
{
    e[++cnt].v = v;
    e[cnt].u = u;
    e[cnt].Next = head[u];
    head[u] = cnt;
}
void tarjan(int now)
{
    dfn[now] = low[now] = ++dep;
    sta[++top] = now;
    vis[now] = 1;
    for (int i = head[now]; ~i; i = e[i].Next)
    {
        int v = e[i].v;
        if (!dfn[v])
        {
            tarjan(v);
            low[now] = min(low[now], low[v]);
        }
        else if (vis[v])
            low[now] = min(low[now], low[v]);
    }
    if (dfn[now] == low[now])
    {
        ++tot;
        while (sta[top] != now)
        {
            vis[sta[top]] = 0;
            num[sta[top]] = tot;
            dis[tot] += p[sta[top--]];
        }
        vis[sta[top]] = 0;
        dis[tot] += p[sta[top]];
        num[sta[top--]] = tot;
    }
}
int dp[MAXN];
int topo()
{
    queue<int> q;
    int ans = -inf;
    int k = 0;
    for (int i = 1; i <= tot; i++)
        if (!in[i])
            q.push(i), dp[i] = dis[i];
    while (!q.empty())
    {
        int now = q.front();
        q.pop();
        k++;
        for (int i = head1[now]; ~i; i = ed[i].Next)
        {
            int v = ed[i].v;
            in[v]--;
            dp[v] = max(dp[v], dp[now] + dis[v]);
            if (!in[v])
                q.push(v);
        }
    }
    for (int i = 1; i <= tot; i++)
        ans = max(ans, dp[i]);
    return ans;
}
int main()
{
    memset(head, -1, sizeof(head));
    memset(head1, -1, sizeof(head1));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &p[i]);
    for (int i = 0; i < m; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    cnt = -1;
    for (int i = 0; i < m; i++)
    {
        int x = e[i].u, y = e[i].v;
        if (num[x] != num[y]) //不在一个强连通分量
        {
            int u = num[x], v = num[y];
            ed[++cnt].u = u;
            ed[cnt].v = v;
            ed[cnt].Next = head1[u];
            head1[u] = cnt;
            in[v]++;
        }
    }
    printf("%d\n", topo());
    return 0;
}

Popular Cows
Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.
Input

  • Line 1: Two space-separated integers, N and M

  • Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.
    Output
  • Line 1: A single integer that is the number of cows who are considered popular by every other cow.

    Sample Input

    3 3
    1 2
    2 1
    2 3

    Sample Output

    1

    解题思路:

    将原图缩点之后重新建图,那么被所有牛崇拜的牛必然在出度为0的一个强连通分量内,如果有一个以上出度为0的强联通分量,则说明不存在被所有牛崇拜的牛,如果出度为0的强联通分量为1那么直接输出该强联通分量内牛的数量即可
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <set>
#include <vector>
#include <cctype>
#include <iomanip>
#include <sstream>
#include <climits>
#include <queue>
#include <stack>
using namespace std;
/*    freopen("k.in", "r", stdin);
    freopen("k.out", "w", stdout); */
//clock_t c1 = clock();
//std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef vector<int, int> VII;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 5e5 + 7;
const ll MAXM = 1e6 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
int n, m;
int head[MAXN], dis[MAXN];
int in[MAXN];
struct Edge
{
    int u, v, Next;
    Edge(int _u = 0, int _v = 0, int _Next = 0) { u = _u, v = _v, Next = _Next; }
} e[MAXN], ed[MAXN];
int cnt = -1;
void add(int u, int v)
{
    e[++cnt].u = u;
    e[cnt].v = v;
    e[cnt].Next = head[u];
    head[u] = cnt;
}
int dfn[MAXN], low[MAXN], dep;
int tot;
int sta[MAXN], top = -1, vis[MAXN];
int num[MAXN];
void tarjan(int now)
{
    dfn[now] = low[now] = ++dep;
    sta[++top] = now;
    vis[now] = 1;
    for (int i = head[now]; ~i; i = e[i].Next)
    {
        int v = e[i].v;
        if (!dfn[v])
        {
            tarjan(v);
            low[now] = min(low[now], low[v]);
        }
        else if (vis[v])
            low[now] = min(low[now], low[v]);
    }
    if (dfn[now] == low[now])
    {
        tot++;
        while (sta[top] != now)
        {
            num[sta[top]] = tot;
            dis[tot]++;
            vis[sta[top--]] = 0;
        }
        vis[sta[top]] = 0;
        dis[tot]++;
        num[sta[top--]] = tot;
    }
}
int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    //重新建图
    for (int i = 0; i < m; i++)
    {
        int x = e[i].u, y = e[i].v;
        if (num[x] != num[y])
        {
            int u = num[x], v = num[y];
            in[u]++; //这里是出度....
        }
    }
    int tt = 0;
    int ans = 0;
    for (int i = 1; i <= tot; i++)
    {
        if (!in[i])
        {
            tt++;
            ans = max(ans, dis[i]);
        }
    }
    if (tt > 1)
        ans = 0;
    printf("%d\n", ans);
    return 0;
}
/* 
7 8
1 2
2 4
4 6
6 7
7 6
1 3
3 5
5 6

 */

猜你喜欢

转载自www.cnblogs.com/graytido/p/11805471.html