一本通tarjan题目

Posted skkyk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一本通tarjan题目相关的知识,希望对你有一定的参考价值。

基本上都是板子, 还没做完

loj

10091 受欢迎的牛

缩点后出度为$ 0 $的点就是欢迎的牛,超过一个点则不存在

#include <bits/stdc++.h>
using namespace std;
const int N = 10000 + 50;
const int M = 50000 + 50;
struct node {
    int next, to;
} edge[M];
int cnt, head[N];
inline void add(int from, int to) { edge[++cnt] = (node){ head[from], to }, head[from] = cnt; }
int n, m, col, top, tot;
int cd[N], color[N], Stack[N], low[N], dfn[N], visited[N], sum[N];
// namespace newgraph{
//  int cnt, head[N];
//  struct node{ int next, to; }edge[M];
//  inline void add(int from, int to) { edge[++cnt] = (node){head[from], to}, head[from] = cnt;} }
//}
void tarjan(int u) {
    Stack[++top] = u, dfn[u] = low[u] = ++tot, visited[u] = 1;
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if (!dfn[v])
            tarjan(v), low[u] = min(low[u], low[v]);
        else if (visited[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]) {
        color[u] = ++col, sum[col]++, visited[u] = 0;
        while (Stack[top] != u) {
            color[Stack[top]] = col;
            sum[col]++;
            visited[Stack[top--]] = 0;
        }
        top--;
    }
}
int main() {
    cin >> n >> m;
    for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), add(u, v);
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    for (int i = 1; i <= n; i++)
        for (int j = head[i]; j; j = edge[j].next)
            if (color[i] != color[edge[j].to])
                cd[color[i]]++;
    int ans = 0, sky;
    for (int i = 1; i <= col; i++)
        if (!cd[i])
            ans++, sky = i;
    if (ans == 1)
        cout << sum[sky];
    else
        puts("0");
    return 0;
}

10093 网络协议

缩点后入度为零的点为第一问,$ max(rd, cd) $ 为第二问。
原因大概就是 形成的 $ DAG $ , 是由几条单向的链合成的, 每条链都要收尾连成环, 故取max

10094 消息的传递

模板

#include <bits/stdc++.h>
using namespace std;
const int N = 1100;
const int M = N * N;
struct node {
    int next, to;
} edge[M];
int cnt, head[N];
inline void add(int from, int to) { edge[++cnt] = (node){ head[from], to }, head[from] = cnt; }
int dfn[N], low[N], visited[N], Stack[N], color[N], rd[N];
int tot, top, col;
int n, ans;
void tarjan(int u) {
    dfn[u] = low[u] = ++tot, Stack[++top] = u, visited[u] = 1;
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if (!dfn[v])
            tarjan(v), low[u] = min(low[u], low[v]);
        else if (visited[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]) {
        color[u] = ++col, visited[u] = 0;
        while (Stack[top] != u) {
            color[Stack[top]] = col;
            visited[Stack[top--]] = 0;
        }
        top--;
    }
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            int x;
            scanf("%d", &x);
            if (x)
                add(i, j);
        }
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    for (int i = 1; i <= n; i++)
        for (int j = head[i]; j; j = edge[j].next)
            if (color[i] != color[edge[j].to])
                rd[color[edge[j].to]]++;
    for (int i = 1; i <= col; i++)
        if (!rd[i])
            ans++;
    cout << ans;
    return 0;
}

10095 间谍网络

缩点后入度为零的点才可以收买,但判断是否有解时神经病了,看的题解。

#include <bits/stdc++.h>
using namespace std;
const int N = 3e3 + 50;
const int M = 8e3 + 50;
const int inf = 1e9 + 7;
struct node {
    int next, to;
} edge[M];
int cnt, head[N];
inline void add(int from, int to) { edge[++cnt] = (node){ head[from], to }, head[from] = cnt; }
int n, p, r;
int cost[N], bribe[N], dfn[N], low[N], color[N], Stack[N], visited[N], rd[N];
int tot, top, col;
void tarjan(int u) {
    Stack[++top] = u, low[u] = dfn[u] = ++tot, visited[u] = 1;
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if (!dfn[v])
            tarjan(v), low[u] = min(low[u], low[v]);
        else if (visited[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]) {
        color[u] = ++col, visited[u] = 0;
        bribe[col] = cost[u];
        while (Stack[top] != u) {
            color[Stack[top]] = col;
            bribe[col] = min(bribe[col], cost[Stack[top]]);
            visited[Stack[top--]] = 0;
        }
        top--;
    }
}
int main() {
    cin >> n >> p;
    for (int i = 1; i <= n; i++) cost[i] = bribe[i] = inf;
    for (int i = 1; i <= p; i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        cost[a] = b;
    }
    cin >> r;
    for (int i = 1; i <= r; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i] && cost[i] != inf)
            tarjan(i);
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            return printf("NO
%d", i), 0;
    for (int i = 1; i <= n; i++)
        for (int j = head[i]; j; j = edge[j].next)
            if (color[i] != color[edge[j].to])
                rd[color[edge[j].to]]++;
    int ans = 0;
    for (int i = 1; i <= col; i++)
        if (!rd[i])
            ans += bribe[i];
    cout << "YES" << '
' << ans;
    return 0;
}

10096 抢掠计划

缩点,建造新图,跑最长路,中途记录答案

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+50;
const int M = 5e5+50;
struct node{ int next, to; }edge[M];
int cnt, head[N];
inline void add(int from, int to) { edge[++cnt] = (node) {head[from], to}, head[from] = cnt; }
int dfn[N], low[N], visited[N], Stack[N], color[N], rd[N], sum[N], cost[N], bar[N], new_bar[N];
int tot, top, col;
int n, m, ans, s, p;
void tarjan(int u) {
    dfn[u] = low[u] = ++tot, Stack[++top] = u, visited[u] = 1;
    for(int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
        else if(visited[v]) low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]) {
        color[u] = ++col, visited[u] = 0;
        sum[col] = cost[u], new_bar[col] = bar[u];
        while(Stack[top] != u) {
            int t = Stack[top];
            color[t] = col;
            sum[col] += cost[t];
            visited[t] = 0;
            new_bar[col] += bar[t];
            top--;
        }
        top--;
    }
}
namespace new_graph{
    struct node{ int next, to; }edge[M];
    int cnt, head[N];
    inline void add(int from, int to) 
    { edge[++cnt] = (node) {head[from], to}, head[from] = cnt; }    
    int dis[N];
    queue<int> q;
    void spfa() {
        q.push(color[s]); dis[color[s]] = sum[color[s]];
        while(!q.empty()) {
            int u = q.front(); q.pop();
            for(int i = head[u]; i; i = edge[i].next) {
                int v = edge[i].to;
                if(dis[v] < dis[u] + sum[v]) {
                    dis[v] = dis[u] + sum[v];
                    if(new_bar[v]) ans = max(ans, dis[v]);
                    q.push(v);
                }
            }
        }
    }
}
int main() {
    cin>>n>>m;
    for(int i = 1, a, b; i <= m; i++) scanf("%d%d", &a, &b), add(a, b);
    for(int i = 1; i <= n; i++) scanf("%d",&cost[i]);
    cin>>s>>p;
    for(int i = 1, x; i <= p; i++) scanf("%d",&x), bar[x] = 1;
    for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
    for(int i = 1; i <= n; i++) 
        for(int j = head[i]; j; j = edge[j].next) 
            if(color[i] != color[edge[j].to]) new_graph::add(color[i], color[edge[j].to]);
    new_graph::spfa();
    cout<<ans;
    return 0;
}

以上是关于一本通tarjan题目的主要内容,如果未能解决你的问题,请参考以下文章

POJ3352 Road Construction Tarjan+边双连通

一本通1058:求一元二次方程

poj-3177(并查集+双联通分量+Tarjan算法)

[Nowcoder] network | Tarjan 边双连通分量 | 缩点 | LCA倍增优化 | 并查集

一本通1154:亲和数

信息学奥赛一本通为啥不通过