AcWing368微分制約システム+ Tarjan SCC +トポロジカル次数DP

題名

ポータルAcWing368

回答

あらゆる種類の関係を微分制約システムに変換し、各ノードの明るさの最小値を解き、それを最長パスの解法に変換します。

ddしましょうdはノードの明るさを表します。T = 1 T = 1T=1時間d [A] -d [B]≥0、d [B] -d [A]≥0d[A] -d [B] \ geq 0、d [B] -d [A] \ geq 0d [ A ]d [ B ]0 d [ B ]d [ A ]0T = 2 T = 2T=2時間d [B] -d [A]≥1d[B] -d [A] \ geq 1d [ B ]d [ A ]1T = 3 T = 3T=3時間d [A] -d [B]≥0d[A] -d [B] \ geq 0d [ A ]d [ B ]0T = 4 T = 4T=4時間d [A] -d [B]≥1d[A] -d [B] \ geq 1d [ A ]d [ B ]1T = 5 T = 5T=5時間d [B] -d [A]≥0d[B] -d [A] \ geq 0d [ B ]d [ A ]0最も暗い明るさを確保するには111d [0] = 0 d [0] = 0に設定d [ 0 ]=0、および制約∀A、d [A] − d [0]≥1\ forall A、d [A] -d [0] \ geq 1A d [ A ]d [ 0 ]1

SPFA SPFA S P F A最長パスを解くO(NM)O(NM)O N M )は実行困難です。微分制約システムのエッジの重みが負でないことに注意してくださいグラフにリングがある場合、リングのエッジの重みの合計は00でなければなりません0 ;それ以外の場合、x> x x> xが表示されますバツ>>xこの種の解決できない状況。

タルジャンタルジャン T R jはAのn個解決するアルゴリズムSCC SCCをS C C、すべての強連結成分にゼロ以外の重みを持つエッジがあるかどうかを判断します。微分制約システムに解がある場合は、トポロジカル次数DPDPを使用します。D Pは、最長パスを解決します。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005, maxm = 3 * 100005;
int N, M, fg, num, low[maxn], dfn[maxn];
int top, st[maxn], nr, rec[maxn];
int scc, sc[maxn], deg[maxn], dp[maxn];
int tot, head[maxn], to[maxm], nxt[maxm], cost[maxm];
int tot_c, hc[maxn], tc[maxm], nc[maxm], cc[maxm];
bool vs[maxn], in[maxn];

inline void add(int x, int y, int z) {
    
     to[++tot] = y, cost[tot] = z, nxt[tot] = head[x], head[x] = tot; }

inline void add_c(int x, int y, int z) {
    
     tc[++tot_c] = y, cc[tot_c] = z, nc[tot_c] = hc[x], hc[x] = tot_c; }

void dfs(int x)
{
    
    
    vs[x] = 1;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i], z = cost[i];
        if (sc[y] != scc)
            continue;
        if (z)
            fg = 0;
        else if (!vs[y])
            dfs(y);
    }
}

void tarjan(int x)
{
    
    
    low[x] = dfn[x] = ++num;
    st[++top] = x, in[x] = 1;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i];
        if (!dfn[y])
        {
    
    
            tarjan(y);
            low[x] = min(low[x], low[y]);
        }
        else if (in[y])
            low[x] = min(low[x], dfn[y]);
    }
    if (low[x] == dfn[x])
    {
    
    
        ++scc, nr = 0;
        int y;
        do
        {
    
    
            y = st[top--], in[y] = 0;
            rec[++nr] = y, sc[y] = scc;
        } while (y != x);
        for (int i = 1; i <= nr; ++i)
            vs[rec[i]] = 0;
        dfs(x);
    }
}

int main()
{
    
    
    scanf("%d%d", &N, &M);
    tot = tot_c = 1;
    for (int i = 1, t, a, b; i <= M; ++i)
    {
    
    
        scanf("%d%d%d", &t, &a, &b);
        if (t == 1)
            add(b, a, 0), add(a, b, 0);
        else if (t == 2)
            add(a, b, 1);
        else if (t == 3)
            add(b, a, 0);
        else if (t == 4)
            add(b, a, 1);
        else if (t == 5)
            add(a, b, 0);
    }
    for (int i = 1; i <= N; ++i)
        add(0, i, 1);
    fg = 1;
    for (int i = 0; i <= N; ++i)
        if (!dfn[i])
            tarjan(i);
    if (!fg)
    {
    
    
        puts("-1");
        return 0;
    }
    for (int i = 0; i <= N; ++i)
        for (int j = head[i]; j; j = nxt[j])
        {
    
    
            int x = sc[i], y = sc[to[j]], z = cost[j];
            if (x != y)
                add_c(x, y, z), ++deg[y];
        }
    queue<int> q;
    for (int i = 1; i <= scc; ++i)
        if (!deg[i])
            q.push(i);
    while (q.size())
    {
    
    
        int x = q.front();
        q.pop();
        for (int i = hc[x]; i; i = nc[i])
        {
    
    
            int y = tc[i], z = cc[i];
            dp[y] = max(dp[y], dp[x] + z);
            if (!--deg[y])
                q.push(y);
        }
    }
    ll res = 0;
    for (int i = 1; i <= N; ++i)
        res += dp[sc[i]];
    printf("%lld\n", res);
    return 0;
}

おすすめ

転載: blog.csdn.net/neweryyy/article/details/115016075