蒟蒻复习之-----Tarjan

来源:互联网 发布:李谷一 知乎 编辑:程序博客网 时间:2024/06/05 14:06

蒟蒻复习之—–Tarjan

//强连通图的判断方法
//作为复习篇不讲原理

[noip2015]信息传递
//就是找一个最小环
//标准的模板题(虽然有很多解法)

#include<iostream>#include<cstdio>#include<cstring>#include<stack>using namespace std;const int maxn = 200000 + 100;int n;struct edge {    int u,v;    int next;}e[maxn];int head[maxn], tot = 0;int read() {    int x = 0, f = 1;    char ch = getchar();    while(ch < '0' || ch > '9') {        if(ch == '-') f = -1;        ch = getchar();    }    while(ch >= '0' && ch <= '9') {        x = x * 10 + ch - '0';        ch = getchar();    }    return x * f;}void add(int u, int v) {    e[++tot] = (edge){u,v,head[u]};    head[u] = tot;}stack<int>q;int dfn[maxn],low[maxn],vis[maxn],cnt = 0,ans = 1<<29;void dfs(int x) {    dfn[x] = low[x] = ++cnt;    q.push(x);    vis[x] = 1;    for(int i = head[x]; i ; i = e[i].next) {        int v = e[i].v;        if(!dfn[v]) {            dfs(v);            low[x] = min(low[x], low[v]);        }        else if(vis[v]) {            low[x] = min(low[x], dfn[v]);        }    }    if(low[x] == dfn[x]) {        int t = x,sum = 0;        do{            vis[t] = 0;            sum++;            t = q.top();            q.pop();        } while(t != x);        if(sum != 1) ans = min(ans,sum);    }}void tarjan() {    for(int i = 1; i <= n; i++) {        if(!dfn[i]) dfs(i);    }}int main() {    n = read();    for(int i = 1; i <= n; i++) {        int v = read();        add(i,v);    }    tarjan();    cout<<ans<<endl;    return 0;}

应用

1.找环

//同上面例题

2.割边割点

//好吧,这个应该不考,不想写了
//QAQ

3.缩点

!!!!!!!这个很重要,缩了点就可以跑DAG了
(DP,蒟蒻瑟瑟发抖~~)–好吧我不会DP
缩点还是会的

[HAOI2006]受欢迎的牛
最水的缩点T

#include<cstdio>#include<iostream>#include<stack>using namespace std;const int maxn = 100000 + 100;int n,m;struct edge {    int u,v,next;}e[maxn * 2];int head[maxn],tot = 0;void add(int u, int v) {    e[++tot] = (edge) {u,v,head[u]};    head[u] = tot;}stack<int>q;int pre[maxn],low[maxn],vis[maxn],cnt = 0,ctt = 0,tp[maxn],dis[maxn];void tarjan(int x) {    pre[x] = low[x] = ++cnt;    q.push(x);    dis[x] = 1;    for(int i = head[x]; i; i = e[i].next) {        int v = e[i].v;        if(!pre[v]) {            tarjan(v);            low[x] = min(low[x],low[v]);        }        else if(dis[v]) {            low[x] = min(low[x],pre[v]);        }    }    if(low[x] == pre[x]){        int t;        ctt++;        do{            t = q.top();            q.pop();            dis[t] = 0;            //打标记            vis[t] = ctt;            tp[ctt]++;        }while(t != x);    }}int d[maxn];int main() {    cin>>n>>m;    for(int i = 1; i <= m; i++) {        int u,v;        cin>>u>>v;        add(u,v);    }    for(int i = 1; i <= n; i++) {        if(!pre[i]){            tarjan(i);        }    }    //注意此处不是for(int i = 1; i <= n; ++) —— for(int j = head[i]; j ; j = e[j].next)    //否则TLE    for(int i = 1; i <= m; i++) {        if(vis[e[i].v] != vis[e[i].u]){            d[vis[e[i].u]]++;        }    }    int tt,sum = 0;    for(int i =1; i <= ctt; i++) {        if(d[i] == 0) {            sum++;            tt = i;        }    }    if(sum != 1){        cout<<'0'<<endl;        return 0;    }    else{        cout<<tp[tt]<<endl;        return 0;    }}