求助,拓扑排序可以 AC 而 tarjan WA
查看原帖
求助,拓扑排序可以 AC 而 tarjan WA
881015
Resstifnurvˆwˆ.tar.gz楼主2024/7/2 20:00

tarjan 版本,点在环上的条件应该是其所在强联通分量大小 ≥2\ge2,tarjan 完之后再 dfs 一遍来判断哪些点可以被攻击到

8080 pts,WA On #5 #9

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <utility>
using namespace std;

// #define IS_ATCODER
// #define IS_MULTI_TESTS
// #define USE_CIN

#ifndef ONLINE_JUDGE
#include <atcoder/all>
using mint = atcoder::modint998244353;
#else
#ifdef IS_ATCODER
#include <atcoder/all>
using mint = atcoder::modint998244353;
#endif
#endif

#define mp make_pair
#define fi first
#define se second
#define sz(a) int(a.size())
using ll = long long;
using pii = pair <int, int>;

inline int read(){
    int ret = 0;
    char ch = ' ', c = getchar();
    while(!('0' <= c && c <= '9')) ch = c, c = getchar();
    while('0' <= c && c <= '9'){
        ret = ret * 10 + (c ^ 48);
        c = getchar();
    }
    return ch == '-' ? -ret : ret;
}

int n, m;
const int N = 600 + 100;
const int M = 2e6 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int p[N];

vector<int> ed[N];

int dfn[N], ts = 0, low[N];
int stk[N], tt = 0;
bool instk[N];
int scc = 0, id[N], sz[N];

void tarjan(int u){
    dfn[u] = ++ts;
    low[u] = dfn[u];
    stk[++tt] = u;
    instk[u] = true;
    for(auto v: ed[u]){
        if(dfn[v] == 0){
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(instk[v]){
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u]){
        scc++;
        int t;
        do{
            t = stk[tt--];
            instk[t] = false;
            id[t] = scc;
            sz[scc]++;
        } while(t != u);
    }
}

bool vis[N];
void dfs(int u){
    if(vis[u] || sz[id[u]] > 1) return ;
    vis[u] = true;
    for(auto v: ed[u]) dfs(v);
}

int to[M], nt[M], idx, h[N];
ll c[M];
inline void add(int x, int y, ll z){
    to[idx] = y, nt[idx] = h[x], c[idx] = z, h[x] = idx++;
    to[idx] = x, nt[idx] = h[y], c[idx] = 0, h[y] = idx++;
}

int S, T;
int cur[N], lv[N];
queue<int> que, empty_queue;

bool bfs(){
    que = empty_queue;
    memset(lv, -1, sizeof(lv));
    lv[S] = 0;
    cur[S] = h[S];
    que.push(S);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = h[u]; i != -1; i = nt[i]){
            int j = to[i];
            if(lv[j] != -1 || c[i] == 0) continue;
            lv[j] = lv[u] + 1;
            cur[j] = h[j];
            que.push(j);
            if(j == T) return true;
        }
    }
    return false;
}

ll find(int u, ll limit){
    if(u == T) return limit;
    ll flow = 0;
    for(int i = cur[u]; flow < limit && i != -1; i = nt[i]){
        cur[u] = i;
        int j = to[i];
        if(lv[j] != lv[u] + 1 || c[i] == 0) continue;
        ll k = find(j, min(limit - flow, c[i]));
        if(k == 0) lv[j] = -1;
        flow += k;
        c[i] -= k;
        c[i ^ 1] += k;
    }
    return flow;
}

ll dinic(){
    ll ans = 0, flow;
    while(bfs()){
        while(flow = find(S, INF)) ans += flow;
    }
    return ans;
}

void solve(){
    memset(h, -1, sizeof(h));
    n = read(), m = read();
    auto ID = [=](int x, int y){
        return (x - 1) * m + y;
    };
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            int id = ID(i, j);
            p[id] = read();
            int cnt = read();
            while(cnt--){
                int x = read() + 1, y = read() + 1;
                int id2 = ID(x, y);
                ed[id].push_back(id2);
            }
            if(j >= 2) ed[id].push_back(id - 1);
        }
    }
    for(int i = 1; i <= n; i++){
        int id = ID(i, m);
        if(dfn[id] == 0) tarjan(id);
    }
    for(int i = 1; i <= n; i++){
        int id = ID(i, m);
        if(!vis[id]) dfs(id);
    }
    for(int u = 1; u <= n * m; u++){
        if(!vis[u]) continue;
        for(auto v: ed[u]){
            if(!vis[v]) continue;
            // printf("add(%d, %d)\n", v, u);
            add(v, u, INF);
        }
    }

    S = 0, T = n * m + 1;
    ll ans = 0;
    for(int u = 1; u <= n * m; u++){
        if(!vis[u]) continue;
        if(p[u] > 0) add(S, u, p[u]), ans += p[u];
        else if(p[u] < 0) add(u, T, -p[u]);
    }
    ans -= dinic();
    printf("%lld\n", ans);
}

int main(){
#ifdef USE_CIN
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
#endif
#ifdef IS_MULTI_TESTS
    int T;
    #ifdef USE_CIN
        cin >> T;
    #else
        T = read();
    #endif
    while(T--) solve();
#else
    solve();
#endif
    return 0;
}
2024/7/2 20:00
加载中...