强连通缩点/最长路 (石油大学组队赛 K: Birdwatching)

Posted Kalzn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了强连通缩点/最长路 (石油大学组队赛 K: Birdwatching)相关的知识,希望对你有一定的参考价值。


题意:给你一个有向图 G G G,和其中的一个点 T T T,你需要找到所有的满足以下条件的点 T ′ T' T
1、 < T ′ , T > ∈ G <T',T>\\in G <T,T>G
2、简单路径 < T ′ , T > <T',T> <T,T>只有一条
题解:这个题起初大家交的很多,因为这个题看起来非常的简单,我也是,然后就直接建反图跑最短路上了。然后就wa了,一看大家都是73point。后来仔细想想,好像这个题没有这么的简单。我一开始的思路是:直接建反图,然后跑可达点。然后枚举每一个T的入点。看看原题是不是有一条边令该点连接一个可达点,如果有,本点不符合要求,否则,符合要求。交上去wa。后来仔细想,发现自己非常白痴,因为这个可达点可以是由这个点可达的,如果此时图中有环,上述结论就不对。
所以正确姿势(我自己的姿势):先把T从图中刨出来,然后跑tarjan,把强连通跑出来缩点,缩成DAG,然后在DAG上以T的所有入点为起点跑最长路,然后枚举所有T的入点,满足以下要求的,是符合要求的点:
1、在 T ′ T' T所属的强联通块内,只有它一个T的入度点。
2、 T ′ T' T所属的强联通块的最长路为0。

下面是ac代码(比赛的时候文件头吸氧了,写了个spfa莫名其妙的过了,赛后一看2900+ms,遂用dij交了一发180ms):

// % everyone
#include <cstdio>
#include<iostream>
#include<cstring>
#include <map>
#include <queue>
#include <set>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <cctype>
#include <time.h>

namespace IO 
    double start_time = 0.0;
    void ct()  start_time = clock(); return; 
    void fast_cin()  std::ios::sync_with_stdio(false); std::cin.tie(); 
    void read_f(int flag = 0)  freopen("0.in", "r", stdin); if(!flag) freopen("0.out", "w", stdout); 
    void run_time()  std::cout << "\\nESC in : " << ( clock() - start_time ) * 1000.0 / CLOCKS_PER_SEC << "ms" << std::endl; 

using namespace IO;
template <typename T>
bool bacmp(const T & a, const T & b)  return a > b; 
template <typename T>
bool pecmp(const T & a, const T & b)  return a < b; 
 
#define ll long long
#define ull unsigned ll
#define _min(x, y) ((x)>(y)?(y):(x))
#define _max(x, y) ((x)>(y)?(x):(y))
#define max3(x, y, z) ( max( (x), max( (y), (z) ) ) )
#define min3(x, y, z) ( min( (x), min( (y), (z) ) ) )
#define pr make_pair
#define pb push_back
using namespace std;

const int N = 3e5+5;
int n, m, cnt;
int he[N], ver[N], ne[N], tot;
int dfn[N], low[N], Belong[N], bcnt;
int st[N], ins[N], top;
map<pair<int, int>, int> mp;
int t;
void add(int x, int y)

    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;

void tarjan(int x)

    if (x == t) return;
    dfn[x] = low[x] = ++cnt;
    ins[x] = 1;
    st[++top] = x;
    for (int i = he[x]; i; i = ne[i])
    
        int y =ver[i];
        if (y == t) continue;
        if (!dfn[y])
        
            tarjan(y);
            low[x] = min(low[x], low[y]);
        
        else if (ins[y]) low[x] = min(low[x], dfn[y]);
    
    if (dfn[x] == low[x])
    
        bcnt++;
        int y;
        do
        
            y = st[top--];
            ins[y] = 0;
            Belong[y] = bcnt;
         while(y != x);
    

int d[N], c[N];
int the[N], tver[N], tne[N], ttot;
void init(int n)

    top = cnt = bcnt = 0;
    tot = 1, ttot = 1;
    for (int i = 0; i <= n; i++)
    
        he[i] = 0, ins[i] = 0, d[i] = 0, c[i] = 0, dfn[i] = 0, low[i] = 0;
        the[i] = 0;
    

void tadd(int x, int y)

    tver[++ttot] = y;
    tne[ttot] = the[x];
    the[x] = ttot;

int vis[N];
vector<int> G[N];
int is[N];
int sum[N];
void dfs(int x)

    if (vis[x]) return;
    vis[x] = 1;
    for (int i = the[x]; i; i = tne[i])
    
        int y = tver[i];
        dfs(y);
    
    for (int i = 0; i < G[x].size(); i++)
    
        is[G[x][i]] = 1;
    

int dis[N], v[N];
void spfa()

    priority_queue<pair<int, int> > q;
    for (int j = he[t]; j; j = ne[j])
    
        int y = ver[j];
        q.push( pr(0, Belong[y]) );
    
    while(q.size())
    
        int te = q.top().second; q.pop();
		if (v[te]) continue;
		v[te] = 1;
        //cout <<"s"<< te << endl;
        for (int i = the[te]; i; i = tne[i])
        
            int y = tver[i];
            if (dis[y] > dis[te] + 1) continue;
            dis[y] = dis[te] + 1;
            q.push(pr(dis[y], y));
        
    

int main()

    int n, m; scanf("%d%d%d", &n, &m, &t);
    t++;
    init(n);
    while(m--)
    
        int x, y;
        scanf("%d%d", &x, &y);
        x++;y++;
        add(y, x);

    
    for (int i = 1; i <= n; i++) if (!dfn[i])
        tarjan(i);
    for (int i = 1; i <= n; i++)
    
        if (i == t) continue;
        for (int j = he[i]; j; j = ne[j])
        
            int  y =ver[j];
            if (y == t) continue;
            if (Belong[i] != Belong[y] && mp[pr(Belong[i], Belong[y])]== 0)
            
                mp[pr(Belong[i], Belong[y])] = 1;
                tadd(Belong[i], Belong[y]);
            
        
    
    spfa();
    for (int j = he[t]; j; j = ne[j])
    
        int y = ver[j];
        sum[Belong[y]]++;
    
    set<int> ans;
    for (int j = he[t]; j; j = ne[j])
    
        int y = ver[j];
        if (dis[Belong[y]] == 0 && sum[Belong[y]] == 1) ans.insert(y);
    
    printf("%d\\n", ans.size());
    for (auto x : ans)
    
        printf("%d\\n", x-1);
    
    return 0;

以上是关于强连通缩点/最长路 (石油大学组队赛 K: Birdwatching)的主要内容,如果未能解决你的问题,请参考以下文章

强连通缩点— HDU1827

poj1236 强连通缩点

poj2553 强连通缩点

强连通缩点

poj2186 强连通缩点

BZOJ 1051: [HAOI2006]受欢迎的牛 强连通缩点