【知识】Topo & 有向图连通性

有向图连通性 & Topo 排序

B3644 【模板】拓扑排序 / 家谱树

#include <iostream>

using namespace std;
const int N=100005;
int du[N], h[N], e[N], ne[N],cnt;
int n;

int q[N];
void add(int a,int b){
    e[++cnt] = b;
    ne[cnt] = h[a];
    h[a] = cnt;
}

void topo(){
    int hh = 0, tt = -1;
    for (int i = 1; i <= n;i++) if(!du[i])
            q[++tt] = i;
    while(hh<=tt){
        int u = q[hh++];
        for (int i = h[u]; i;i=ne[i]){
            if(!--du[e[i]])
                q[++tt] = e[i];
        }
        
    }
    for (int i = 0; i <= tt;i++)
        cout << q[i] << " ";
}
int main(){

    cin >> n;
    for (int i = 1; i <= n;i++){
        int a;
        while(cin>>a && a){
            add(i, a);
            du[a]++;
        }
    }

    topo();
    return 0;
}

P1347 排序

就是裸 Topo 排序。

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << '=' << x << endl

inline int rd()
{
    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 print(int x)
{
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
    return;
}

namespace Star_F
{

    const int mx = 30;

    int n, m;
    vector<int> e[mx];
    int d[mx];
    int a[mx];
    stack<int> s;
    bool v[mx];
    int mk;

    bool tp(int r)
    {
        int sz = 0;
        bool fn = true;
        int t[mx];
        for (int i = 0; i < n; i++)
        {
            t[i] = d[i];
            if (!d[i])
                s.push(i), v[i] = true;
        }
        while (!s.empty())
        {
            if (s.size() > 1)
                fn = false;
            int k = s.top();
            a[sz++] = k;
            s.pop();
            for (int i = 0; i < e[k].size(); i++)
                t[e[k][i]]--;
            for (int i = 0; i < n; i++)
                if (!t[i] && !v[i])
                    s.push(i), v[i] = true;
        }
        if (sz < n)
            return false;
        if (fn && !mk)
            mk = r;
        return true;
    }

    void Main()
    {
        n = rd();
        m = rd();
        int flaggg = 0;
        FOR(i, 1, m)
        {
            char c[3];
            scanf("%s", c);
            int x = c[0] - 'A', y = c[2] - 'A';
            e[x].push_back(y);
            d[y]++;
            if (mk)
            {
                cout << "Sorted sequence determined after " << mk << " relations: ";
                for (int i = 0; i < n; i++)
                    cout << char(a[i] + 'A');
                cout << ".";
                flaggg = 1;
            }
            if (!tp(i)&&flaggg==0)
            {
                cout << "Inconsistency found after " << i << " relations.";
                return;
            }
            memset(v, false, sizeof(v));
        }
        if (mk&&flaggg==0)
        {
            cout << "Sorted sequence determined after " << mk << " relations: ";
            for (int i = 0; i < n; i++)
                cout << char(a[i] + 'A');
            cout << ".";
        }
        else if(flaggg==0)
        {
            cout << "Sorted sequence cannot be determined.";
        }
    }

}

signed main()
{
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    return Star_F::Main(), 0;
}

Directing Edges

首先,无解的情况一定是原图有向边成环。

有解的话原图给定的有向边一定形成 DAG。

所以进行拓扑排序,对于所有无向边,让拓扑编号小的指向拓扑编号大的即可。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
    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 << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
#define rd rd()

void wt(int x){
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        wt(x / 10);
    putchar(x % 10 + '0');
    return;
}
void wt(char x){
    putchar(x);
}
void wt(int x, char k){
    wt(x),putchar(k);
}

namespace Star_F{
    const int N = 200005;
    int h[N], e[N], ne[N], idx;
    int du[N], topo[N], tot;
    int T, n, m;
    void add(int u,int v){
        e[++idx] = v, ne[idx] = h[u], h[u] = idx;
    }
    bool toposort(int n){
        queue<int> q;
        for (int i = 1; i <= n;i++) 
            if(du[i]==0)
                q.push(i);
        while(!q.empty()){
            int x = q.front();
            q.pop();
            topo[x] = ++tot;
            for (int i = h[x]; i;i=ne[i]){
                int y = e[i];
                if(--du[y]==0)
                    q.push(y);
            }
        }
        if(tot<n)
            return 0;
        return 1;
    }
    void Main(){
        cin >> T;
        while(T--){
            int n, m;
            cin >> n >> m;
            memset(h, 0, sizeof(h));
            memset(du, 0, sizeof(du));
            idx = tot = 0;
            vector<PII> t;
            for (int i = 1; i <= m;i++){
                int opt, x, y;
                cin >> opt >> x >> y;
                if(opt==1){
                    add(x, y), du[y]++;
                }
                    
                else
                    t.push_back({x, y});
            }
            if(!toposort(n)){
                cout << "NO" << endl;
                continue;
            }
            cout << "YES" << endl;
            for (int i = 1; i <= n;i++){
                for(int j=h[i];j;j=ne[j]){
                    cout << i << " " << e[j] << endl;
                }
            }
            for (int i = 0; i < t.size();i++){
                int x = t[i].fi, y = t[i].se;
                if(topo[x]>=topo[y])
                    swap(x, y);
                cout << x << " " << y << endl;
            }
        }
    }

}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ClockA;
    int T=1;
    // T=rd;
    while(T--) Star_F::Main();
    // ClockB;
    return 0;
}


/*
*          ▀▀▀██████▄▄▄       _______________
*          ▄▄▄▄▄  █████████▄  /                 \
*         ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG!  |
*      ▀▀█████▄▄ ▀██████▄██ | _________________/
*       ▀▄▄▄▄▄  ▀▀█▄▀█════█▀ |/
*            ▀▀▀▄  ▀▀███ ▀       ▄▄
*         ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌   ______________________________
*       ██▀▄▄▄██▀▄███▀ ▀▀████      ▄██  █                               \\
*    ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███     ▌▄▄▀▀▀▀█_____________________________ //
*    ▌    ▐▀████▐███▒▒▒▒▒▐██▌
*    ▀▄▄▄▄▀   ▀▀████▒▒▒▒▄██▀
*              ▀▀█████████▀
*            ▄▄██▀██████▀█
*          ▄██▀     ▀▀▀  █
*         ▄█             ▐▌
*     ▄▄▄▄█▌              ▀█▄▄▄▄▀▀▄
*    ▌     ▐                ▀▀▄▄▄▀
*     ▀▀▄▄▀     ██
* \  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌           Name: Star_F              ▀ ▀
*  - ▌                            (o)          ▀
* /- ▌            Go Go Go !               ▀ ▀
* /  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/

P2419 USACO08JAN] Cow Contest S

Floyd 算法轻松解决!

fi,j=fi,j|(fi,k&fk,j)表示i能否走到j,即要么一开始 i 能到 j ,要么 i 能到 kk 再能到 j

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
    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 << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
#define rd rd()

void wt(int x){
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        wt(x / 10);
    putchar(x % 10 + '0');
    return;
}
void wt(char x){
    putchar(x);
}
void wt(int x, char k){
    wt(x),putchar(k);
}

namespace Star_F{
    const int N = 105;
    int n, m, f[N][N], ans;
    void Main(){
        cin >> n >> m;
        for (int i = 1; i <= m;i++){
            int u, v;
            cin >> u >> v;
            f[u][v] = 1;
        }
        for (int k = 1; k <= n;k++)
            for (int i = 1; i <= n;i++)
                for (int j = 1; j <= n;j++)
                    f[i][j] = f[i][j] | f[i][k] & f[k][j];
        for (int i = 1; i <= n;i++){
            int t = 1;
            for (int j = 1; j <= n;j++){
                if(i==j)
                    continue;
                t = t & (f[i][j] | f[j][i]);
            }
            ans += t;
        }
        cout << ans << endl;
    }

}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ClockA;
    int T=1;
    // T=rd;
    while(T--) Star_F::Main();
    // ClockB;
    return 0;
}


/*
*          ▀▀▀██████▄▄▄       _______________
*          ▄▄▄▄▄  █████████▄  /                 \
*         ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG!  |
*      ▀▀█████▄▄ ▀██████▄██ | _________________/
*       ▀▄▄▄▄▄  ▀▀█▄▀█════█▀ |/
*            ▀▀▀▄  ▀▀███ ▀       ▄▄
*         ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌   ______________________________
*       ██▀▄▄▄██▀▄███▀ ▀▀████      ▄██  █                               \\
*    ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███     ▌▄▄▀▀▀▀█_____________________________ //
*    ▌    ▐▀████▐███▒▒▒▒▒▐██▌
*    ▀▄▄▄▄▀   ▀▀████▒▒▒▒▄██▀
*              ▀▀█████████▀
*            ▄▄██▀██████▀█
*          ▄██▀     ▀▀▀  █
*         ▄█             ▐▌
*     ▄▄▄▄█▌              ▀█▄▄▄▄▀▀▄
*    ▌     ▐                ▀▀▄▄▄▀
*     ▀▀▄▄▀     ██
* \  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌           Name: Star_F              ▀ ▀
*  - ▌                            (o)          ▀
* /- ▌            Go Go Go !               ▀ ▀
* /  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/

P1983 [NOIP 2013 普及组] 车站分级

将不需要停靠的向需要停靠的连边,满足拓扑关系。

TopoSort 一下即可。

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << '=' << x << endl

inline int rd() {
    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 print(int x) {
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
    return;
}

namespace Star_F {

    const int MAXN = 1005;
    int s[MAXN][MAXN], n, m, ans, in_degree[MAXN], vis[MAXN], pd[MAXN][MAXN];
    queue<pair<int, int>> q;
    vector<int> g[MAXN];

    inline void bfs() {
        for (int i = 1; i <= n; ++i) {
            if (in_degree[i] == 0)
                q.push(make_pair(i, 1));
        }
        ans = 1;
        while (!q.empty()) {
            int u = q.front().first;
            int val = q.front().second;
            q.pop();
            for (int v : g[u]) {
                in_degree[v]--;
                if (in_degree[v] == 0) {
                    q.push(make_pair(v, val + 1));
                    ans = max(ans, val + 1);
                }
            }
        }
    }

    void Main() {
        n = rd();
        m = rd();
        for (int i = 1; i <= m; ++i) {
            s[i][0] = rd();
            memset(vis, 0, sizeof(vis));
            for (int j = 1; j <= s[i][0]; ++j) {
                int x = rd();
                s[i][j] = x;
                vis[x] = true;
            }
            for (int j = s[i][1]; j <= s[i][s[i][0]]; ++j) {
                if (vis[j]) continue;
                for (int k = 1; k <= s[i][0]; ++k) {
                    if (!pd[j][s[i][k]]) {
                        in_degree[s[i][k]]++;
                        g[j].push_back(s[i][k]);
                        pd[j][s[i][k]] = true;
                    }
                }
            }
        }
        bfs();
        cout << ans << endl;
    }

}

signed main() {
    // freopen(".in", "r", stdin);
    // freopen(".out", "w", stdout);
    return Star_F::Main(), 0;
}

P3243[ HNOI2015] 菜肴制作

最优解就是符合条件的排列中,反序列的字典序最大的排列。

定义两个拓扑序中更优的一个为“最小序”更小的拓扑序。

求证:一个 DAG 的拓扑序中“最小序”最小的的一个拓扑序,是反向字典序最大的一个。

证明:

首先,当 |V|=1 时结论显然。

其次,假设结论对于 |V|<n 均成立。设图 G=(V,E) 中最小点编号为 x,其中 |V|=n,则整个点集分为两部分:

  • S={z | 存在一条路径 zx}
  • T=VS

特别地,有 xS

Lemma 1:令 m:=|S|。则最小序最小的拓扑序 a 一定满足 {ax|1xm}=Sam=x

证明:由于 x 在拓扑序上的位置越小,最小序就越小,所以 x 尽可能靠前更优。由拓扑序的定义,S{x} 中的所有点在拓扑序上一定排在 x 之前。

所以 ap=xpm 的充分条件。于是最小的最小序满足 p=m

现将整个图可以分成三个子图,其点集分别为$ S-{x}{x}$ 和 T

由于 |S|+|T|=n,所以 |S{x}|,|T|<n,由假设得其结论成立。

因为 x 是编号最小的,将 x 向后移不能获得更大的反向字典序。而 S{x},T 的结论已证。于是对于图 G 结论成立。

所以对于任意的 DAG,由数学归纳法得结论均成立。

证毕。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
    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 << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
#define rd rd()

void wt(int x){
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        wt(x / 10);
    putchar(x % 10 + '0');
    return;
}
void wt(char x){
    putchar(x);
}
void wt(int x, char k){
    wt(x),putchar(k);
}

namespace Star_F{
    const int N = 100005;
    int t, n, m, x, y, cnt;
    int du[N], ans[N];
    vector<int> G[N];
    priority_queue<int> q;
    void Main(){
        cin >> t;
        while(t--){
            cin >> n >> m;
            cnt = 0;
            for(int i=1;i<=n;i++)
                ans[i] = du[i] = 0;
            for(int i=1;i<=n;i++)
                G[i].clear();
            for(int i=1;i<=m;i++){
                cin >> x >> y;
                du[x]++;
                G[y].push_back(x);
            }
            for(int i=1;i<=n;i++)
                if(!du[i])
                    q.push(i);
            while(!q.empty()){
                int u = q.top();
                q.pop();
                for (int i = 0; i < G[u].size(); i++){
                    int x = G[u][i];
                    du[x]--;
                    if(!du[x])
                        q.push(x);
                }
                ans[++cnt] = u;
            }
            if(cnt<n)
                cout << "Impossible!";
            else
                for (int i = cnt; i >= 1; i--)
                    cout << ans[i] << " ";
            cout << endl;
        }
    }
}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ClockA;
    int T=1;
    // T=rd;
    while(T--) Star_F::Main();
    // ClockB;
    return 0;
}


/*
*          ▀▀▀██████▄▄▄       _______________
*          ▄▄▄▄▄  █████████▄  /                 \
*         ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG!  |
*      ▀▀█████▄▄ ▀██████▄██ | _________________/
*       ▀▄▄▄▄▄  ▀▀█▄▀█════█▀ |/
*            ▀▀▀▄  ▀▀███ ▀       ▄▄
*         ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌   ______________________________
*       ██▀▄▄▄██▀▄███▀ ▀▀████      ▄██  █                               \\
*    ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███     ▌▄▄▀▀▀▀█_____________________________ //
*    ▌    ▐▀████▐███▒▒▒▒▒▐██▌
*    ▀▄▄▄▄▀   ▀▀████▒▒▒▒▄██▀
*              ▀▀█████████▀
*            ▄▄██▀██████▀█
*          ▄██▀     ▀▀▀  █
*         ▄█             ▐▌
*     ▄▄▄▄█▌              ▀█▄▄▄▄▀▀▄
*    ▌     ▐                ▀▀▄▄▄▀
*     ▀▀▄▄▀     ██
* \  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌           Name: Star_F              ▀ ▀
*  - ▌                            (o)          ▀
* /- ▌            Go Go Go !               ▀ ▀
* /  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/

P3275 [SCOI2011] 糖果

先缩点,再用 TopoSort 求最长路即可。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10, M = 6e5 + 10;

int n, m;
int h[N], nh[N], e[M], ne[M], w[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt;
int Size[N];

void add(int h[], int a, int b, int c)
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}

void tarjan(int u)
{
    dfn[u] = low[u] = ++timestamp;
    stk[++top] = u, in_stk[u] = true;

    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (!dfn[j])
        {
            tarjan(j);
            low[u] = min(low[u], low[j]);
        }
        else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
    }

    if (dfn[u] == low[u])
    {
        ++scc_cnt;
        int y;
        do
        {
            y = stk[top--];
            in_stk[y] = false;
            id[y] = scc_cnt;
            Size[scc_cnt] ++;
        } while (y != u);
    }
}

int d[N], q[N];
int dp[N];
void topsort()
{
    int hh = 0, tt = -1;
    for (int i = 1; i <= n; i++)
        if (!d[i])
            q[++tt] = i, dp[i] = 1;

    while (hh <= tt)
    {
        int t = q[hh++];
        for (int i = nh[t]; ~i; i = ne[i])
        {
            int j = e[i];
            dp[j] = max(dp[j], dp[t] + w[i]);
            if (--d[j] == 0)
                q[++tt] = j;
        }
    }
}


int main()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);
    while (m--)
    {
        int x, a,b;
        scanf("%d%d%d", &x, &a, &b);
        if (x == 1) add(h,a, b, 0), add(h,b, a, 0);
        else if (x == 2) add(h,a, b, 1);
        else if (x == 3) add(h,b, a, 0);
        else if (x == 4) add(h,b, a, 1);
        else add(h,a, b, 0);
    }

    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);

    memset(nh, -1, sizeof nh);
    for (int i = 1; i <= n; i++)
    {
        for (int j = h[i]; ~j; j = ne[j])
        {
            int v = e[j];
            int x = id[i], y = id[v];

            if (x == y && w[j] == 1)
            {
                cout << -1;
                return 0;
            }

            if (x != y)
            {
                add(nh, x, y, w[j]);
                d[y] ++;
            }
        }
    }

    topsort();

    ll res = 0;
    for (int i = 1; i <= scc_cnt; i++)
        res += (ll)dp[i] * Size[i];
    cout << res;
    return 0;
}

P2863 [USACO06JAN] The Cow Prom S

求点个数大于 1 的强连通分量个数。

Tarjan 缩点,判断是否大于 1 即可。

#include<bits/stdc++.h>
using namespace std;

const int N = 100005;
int n, m, tim, top;
int h[N], e[N], ne[N], idx;
int dfn[N], low[N], s[N], ans;
bool vis[N];

void add(int u, int v){
    e[++idx] = v, ne[idx] = h[u], h[u] = idx;
}

void tarjan(int x){
    low[x] = dfn[x] = ++tim;
    s[++top] = x; vis[x] = 1; 
    for (int i = h[x]; i; i = ne[i]){
        int v = e[i];
        if (!dfn[v]) {
            tarjan(v);
            low[x] = min(low[x], low[v]);
        }
        else if (vis[v])
            low[x] = min(low[x], low[v]);
    }
    if (dfn[x] == low[x]){
        int y;
        if(x!=s[top]) ans++;
        while (y = s[top--]){
            vis[y] = 0;
            if (x == y) break;
        }
    }
}

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 (!dfn[i]) tarjan(i);
    cout << ans << endl;
    return 0;
}

How Many Paths?

就是搜索题,具体看代码

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
    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 << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
#define rd rd()

void wt(int x){
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        wt(x / 10);
    putchar(x % 10 + '0');
    return;
}
void wt(char x){
    putchar(x);
}
void wt(int x, char k){
    wt(x),putchar(k);
}

namespace Star_F{
    const int N = 400005;
    vector<int> G[N];
    int n, m, o[N], vis[N], in[N];
    void init(){
        
        for (int i = 0; i <= n; i++)
            vis[i] = 0;
        for (int i = 0; i <= n;i++)
            in[i] = 0;
    }

    void dfs(int x){
        vis[x] = in[x] = o[x] = 1;
        for (int i = 0; i < G[x].size();i++){
            int y = G[x][i];
            if(!vis[y])
                dfs(y);
            else if(in[y])
                o[y] = -1;
            else if(o[y]!=-1)
                o[y] = 2;
        }
        in[x] = 0;
    }

    void dfs2(int x, int op){
        vis[x] = 1;
        if(o[x]!=-1&&o[x]!=op)
            o[x] = op;
        for (int i = 0; i < G[x].size(); i++){
            int y = G[x][i];
            if(!vis[y])
                dfs2(y, op);
        }
    }
    void Main(){
        cin >> n >> m;
        for (int i = 0; i <= n;i++)
            G[i].clear(), o[i] = 0;
        for (int i = 1; i <= m;i++){
            int u, v;
            cin >> u >> v;
            G[u].push_back(v);
        }
        init();
        dfs(1);
        init();
        for (int i = 1; i <= n;i++)
            if(o[i]==2) 
                dfs2(i, 2);
        init();
        for (int i = 1; i <= n;i++) 
            if(o[i]==-1)
                dfs2(i, -1);
        for (int i = 1; i <= n;i++)
            cout << o[i] << " ";
        cout << endl;
    }

}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ClockA;
    int T=1;
    T=rd;
    while(T--) Star_F::Main();
    // ClockB;
    return 0;
}


/*
*          ▀▀▀██████▄▄▄       _______________
*          ▄▄▄▄▄  █████████▄  /                 \
*         ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG!  |
*      ▀▀█████▄▄ ▀██████▄██ | _________________/
*       ▀▄▄▄▄▄  ▀▀█▄▀█════█▀ |/
*            ▀▀▀▄  ▀▀███ ▀       ▄▄
*         ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌   ______________________________
*       ██▀▄▄▄██▀▄███▀ ▀▀████      ▄██  █                               \\
*    ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███     ▌▄▄▀▀▀▀█_____________________________ //
*    ▌    ▐▀████▐███▒▒▒▒▒▐██▌
*    ▀▄▄▄▄▀   ▀▀████▒▒▒▒▄██▀
*              ▀▀█████████▀
*            ▄▄██▀██████▀█
*          ▄██▀     ▀▀▀  █
*         ▄█             ▐▌
*     ▄▄▄▄█▌              ▀█▄▄▄▄▀▀▄
*    ▌     ▐                ▀▀▄▄▄▀
*     ▀▀▄▄▀     ██
* \  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌           Name: Star_F              ▀ ▀
*  - ▌                            (o)          ▀
* /- ▌            Go Go Go !               ▀ ▀
* /  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/

P3387 【模板】缩点

#include<bits/stdc++.h>
using namespace std;

const int maxn = 10000 + 15;
int n, m, sum, tim, top, s;
int p[maxn], head[maxn], sd[maxn], dfn[maxn], low[maxn]; // dfn(u) 为节点 u 被搜索到时的次序编号(时间戳),low(u) 为 u 或 u 的子树能够追溯到的最早的栈中节点的次序号
int stac[maxn], vis[maxn]; // 栈 stac 用于判断当前是否在栈中
int h[maxn], in[maxn], dist[maxn];

struct EDGE
{
    int to, next, from;
} edge[maxn * 10], ed[maxn * 10];

// 添加边函数,将一条从 x 到 y 的边加入邻接表
void add(int x, int y)
{
    edge[++sum].next = head[x];
    edge[sum].from = x;
    edge[sum].to = y;
    head[x] = sum;
}

// Tarjan 算法用于求解强连通分量
void tarjan(int x)
{
    low[x] = dfn[x] = ++tim;
    stac[++top] = x; vis[x] = 1; // 将 x 入栈,并标记 x 已访问
    for (int i = head[x]; i; i = edge[i].next)
    {
        int v = edge[i].to;
        if (!dfn[v]) {
            tarjan(v);
            low[x] = min(low[x], low[v]);
        }
        else if (vis[v])
        {
            low[x] = min(low[x], low[v]);
        }
    }
    if (dfn[x] == low[x])
    {
        int y;
        while (y = stac[top--])
        {
            sd[y] = x;
            vis[y] = 0;
            if (x == y) break;
            p[x] += p[y];
        }
    }
}

// 拓扑排序
int topo()
{
    queue<int> q;
    for (int i = 1; i <= n; i++)
        if (sd[i] == i && !in[i])
        {
            q.push(i);
            dist[i] = p[i];
        }
    while (!q.empty())
    {
        int k = q.front(); q.pop();
        for (int i = h[k]; i; i = ed[i].next)
        {
            int v = ed[i].to;
            dist[v] = max(dist[v], dist[k] + p[v]);
            in[v]--;
            if (in[v] == 0) q.push(v);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
        ans = max(ans, dist[i]);
    return ans;
}

int main()
{
    scanf("%d%d", &n, &m); // 输入节点数和边数
    for (int i = 1; i <= n; i++)
        scanf("%d", &p[i]); // 输入每个节点的权值
    for (int i = 1; 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); // 对每个节点运行 Tarjan 算法
    for (int i = 1; i <= m; i++)
    {
        int x = sd[edge[i].from], y = sd[edge[i].to];
        if (x != y)
        {
            ed[++s].next = h[x];
            ed[s].to = y;
            ed[s].from = x;
            h[x] = s;
            in[y]++;
        }
    }
    printf("%d", topo()); // 输出拓扑排序的结果
    return 0;
}

Bertown roads

因为一个强连通分量中不好含割边,所以主要存在割边就是无解。

然后一边 Tarjan 一边记录路径就行。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
    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 << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
#define rd rd()

void wt(int x){
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        wt(x / 10);
    putchar(x % 10 + '0');
    return;
}
void wt(char x){
    putchar(x);
}
void wt(int x, char k){
    wt(x),putchar(k);
}

namespace Star_F{
    const int N = 1000005;
    int n, m, t, cnt;
    int low[N], dfn[N];
    int h[N], ne[N], e[N], idx;
    bool flag, vis[N];
    PII ans[N];

    void add(int u,int v){
        e[++idx] = v, ne[idx] = h[u],h[u] = idx;
    }

    void tarjan(int x,int fa){
        vis[x] = 1;
        low[x] = dfn[x] = ++t;
        for (int i = h[x]; i;i=ne[i]){
            int y = e[i];
            if(!vis[y]){
                tarjan(y, x);
                ans[++cnt] = {x, y};
                low[x] = min(low[x], low[y]);
            }
            if(low[y]>dfn[x]){
                flag = 1;
                return;
            }
            else if(y!=fa&&dfn[y]<dfn[x]){
                low[x] = min(low[x], dfn[y]);
                ans[++cnt] = {x, y};
            }
        }
    }
    void Main(){
        cin >> n >> m;
        while(m--){
            int x, y;
            cin >> x >> y;
            add(x, y), add(y, x);
        }
        tarjan(1, 0);
        if(flag){
            cout << 0 << endl;
            exit(0);
        }
        for (int i = 1; i <= cnt;i++){
            cout << ans[i].fi << " " << ans[i].se << endl;
        }
    }

}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ClockA;
    int T=1;
    // T=rd;
    while(T--) Star_F::Main();
    // ClockB;
    return 0;
}


/*
*          ▀▀▀██████▄▄▄       _______________
*          ▄▄▄▄▄  █████████▄  /                 \
*         ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG!  |
*      ▀▀█████▄▄ ▀██████▄██ | _________________/
*       ▀▄▄▄▄▄  ▀▀█▄▀█════█▀ |/
*            ▀▀▀▄  ▀▀███ ▀       ▄▄
*         ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌   ______________________________
*       ██▀▄▄▄██▀▄███▀ ▀▀████      ▄██  █                               \\
*    ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███     ▌▄▄▀▀▀▀█_____________________________ //
*    ▌    ▐▀████▐███▒▒▒▒▒▐██▌
*    ▀▄▄▄▄▀   ▀▀████▒▒▒▒▄██▀
*              ▀▀█████████▀
*            ▄▄██▀██████▀█
*          ▄██▀     ▀▀▀  █
*         ▄█             ▐▌
*     ▄▄▄▄█▌              ▀█▄▄▄▄▀▀▄
*    ▌     ▐                ▀▀▄▄▄▀
*     ▀▀▄▄▀     ██
* \  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌           Name: Star_F              ▀ ▀
*  - ▌                            (o)          ▀
* /- ▌            Go Go Go !               ▀ ▀
* /  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/

Reachability from the Capital

首先还是缩点后成为 DAG,然后对于一个入度为 0 的点,一定需要连接一条边。

注意特判起点入度为 0 答案不用 +1

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
    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 << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
#define rd rd()

void wt(int x){
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        wt(x / 10);
    putchar(x % 10 + '0');
    return;
}
void wt(char x){
    putchar(x);
}
void wt(int x, char k){
    wt(x),putchar(k);
}

namespace Star_F{
    const int N = 5005, M = 1000005;
    int ss, n, m, s[N], t, top, cnt, ans;
    int h[N], e[M], ne[M], idx;
    int dfn[N],low[N],id[N],in[N];
    int u[N], v[N];
    bool vis[N];

    void add(int u,int v){
        e[++idx] = v, ne[idx] = h[u], h[u] = idx;
    }

    void tarjan(int u){
        vis[u] = 1;
        dfn[u] = low[u] = ++t;
        s[++top] = u;
        for (int i = h[u]; i;i=ne[i]){
            int v = e[i];
            if(!dfn[v]){
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if(vis[v])
                low[u] = min(low[u], low[v]);
        }
        if(low[u]==dfn[u]){
            cnt++;
            int y;
            do{
                y = s[top--];
                vis[y] = 0;
                id[y] = cnt;
            } while (y != u);
        }

    }
    void Main(){
        cin >> n >> m >> ss;
        for (int i = 1; i <= m;i++){
            cin >> u[i] >> v[i];
            add(u[i], v[i]);
        }
        for (int i = 1; i <= n;i++)
            if(!dfn[i])
                tarjan(i);
        for (int i = 1; i <= m;i++){
            if(id[u[i]]!=id[v[i]])
                in[id[v[i]]]++;
        }
        for (int i = 1; i <= cnt;i++) if(!in[i])
            ans++;
        cout << ans - !in[id[ss]] << endl;
    }
}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ClockA;
    int T=1;
    // T=rd;
    while(T--) Star_F::Main();
    // ClockB;
    return 0;
}


/*
*          ▀▀▀██████▄▄▄       _______________
*          ▄▄▄▄▄  █████████▄  /                 \
*         ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG!  |
*      ▀▀█████▄▄ ▀██████▄██ | _________________/
*       ▀▄▄▄▄▄  ▀▀█▄▀█════█▀ |/
*            ▀▀▀▄  ▀▀███ ▀       ▄▄
*         ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌   ______________________________
*       ██▀▄▄▄██▀▄███▀ ▀▀████      ▄██  █                               \\
*    ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███     ▌▄▄▀▀▀▀█_____________________________ //
*    ▌    ▐▀████▐███▒▒▒▒▒▐██▌
*    ▀▄▄▄▄▀   ▀▀████▒▒▒▒▄██▀
*              ▀▀█████████▀
*            ▄▄██▀██████▀█
*          ▄██▀     ▀▀▀  █
*         ▄█             ▐▌
*     ▄▄▄▄█▌              ▀█▄▄▄▄▀▀▄
*    ▌     ▐                ▀▀▄▄▄▀
*     ▀▀▄▄▀     ██
* \  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌           Name: Star_F              ▀ ▀
*  - ▌                            (o)          ▀
* /- ▌            Go Go Go !               ▀ ▀
* /  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
posted @   Star_F  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示