【CF1137C】 Museums Tour 拆点+缩点

https://codeforc.es/contest/1137/problem/C

题意

给你n个点,每个点有k天博物馆开放时间的安排表。

有m条单向道路,走过一条边需要一个晚上,经过后就是第二天的意思。

问在无穷大的时间里,可以参观多少不同的博物馆。

思路

我们把每个点都拆出k个点,有单向边相连就从$(u,i) -> (v, (i+1)%k)$。

缩点跑出DAG,然后DP出最多的博物馆参观数。

 

这里就要考虑直接DP是否能行。假设有一条$(u,i) -> (u, j)$的边,由于没有自环且是单向边,所以一定可以通过循环,可以从$(u,j)$再走到$(u,i)$,所以这两个点会缩在一起。

由于这种做法缩点时递归很深,我是通过inline优化的,开$O(3)$好像也可以。

 

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr << #x << " := " << x << endl;
#define bug cerr << "-----------------------" << endl;
#define FOR(a, b, c) for (int a = b; a <= c; ++a)
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

template <class T>
void _R(T &x) {
    cin >> x;
}
void _R(int &x) {
    scanf("%d", &x);
}
void _R(ll &x) {
    scanf("%lld", &x);
}
void _R(double &x) {
    scanf("%lf", &x);
}
void _R(char &x) {
    scanf(" %c", &x);
}
void _R(char *x) {
    scanf("%s", x);
}
void R() {
}
template <class T, class... U>
void R(T &head, U &... tail) {
    _R(head);
    R(tail...);
}

template <typename T>
inline T read(T &x) {
    x = 0;
    int f = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    return x = f ? -x : x;
}
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

/**********showtime************/
const int maxn = 5000009;

//    vector<int>mp[maxn];
int n,
    m, k;
int getid(int x, int i) {
    return (x - 1) * k + i + 1;
}
struct E {
    int u, v;
    int nxt;
} edge[maxn];
int gtot = 0, head[maxn];
void addedge(int u, int v) {
    edge[gtot].u = u;
    edge[gtot].v = v;
    edge[gtot].nxt = head[u];
    head[u] = gtot++;
}
set<int> dpmp[maxn];
char str[55];
int dp[maxn], a[maxn];
int belong[maxn], dfn[maxn], low[maxn];
bool vis[maxn];
bool flag[maxn];
//  int used[maxn];
int tim, scc_cnt;

//stack<int>st;
queue<int>
    que;
int st[5000009];
int top = 0;
inline void dfs(int u) {
    dfn[u] = low[u] = ++tim;
    //                st.push(u);
    st[++top] = u;
    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int v = edge[i].v;
        if (!dfn[v]) dfs(v);
        if (!belong[v]) low[u] = min(low[u], low[v]);
    }
    if (dfn[u] == low[u]) {
        scc_cnt++;
        int now;
        while (true) {
            now = st[top];
            top--;
            belong[now] = scc_cnt;
            if (flag[now]) {
                int id = (now - 1) / k + 1;
                if (vis[id] == 0) {
                    que.push(id);
                    vis[id] = 1;
                    a[scc_cnt]++;
                }
            }
            if (now == u) break;
        }
        while (!que.empty()) {
            int u = que.front();
            que.pop();
            vis[u] = 0;
        }
    }
}
int ans = 0;

void cal(int s) {
    queue<int> que;
    dp[s] = a[s];
    que.push(s);
    ans = max(ans, a[s]);
    while (!que.empty()) {
        int u = que.front();
        que.pop();
        vis[u] = 0;
        for (int v : dpmp[u]) {
            dp[v] = max(dp[v], dp[u] + a[v]);
            ans = max(ans, dp[v]);
            if (vis[v] == 0) {
                vis[v] = 1;
                que.push(v);
            }
        }
    }
}
int main() {
    memset(head, -1, sizeof(head));
    R(n, m, k);
    for (int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        for (int j = 0; j < k; j++) {
            addedge(getid(u, j), getid(v, (j + 1) % k));
        }
    }
    for (int i = 1; i <= n; i++) {
        scanf("%s", str);
        for (int j = 0; j < k; j++) {
            flag[getid(i, j)] = (str[j] == '1');
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < k; j++)
            if (!dfn[getid(i, j)]) dfs(getid(i, j));
    }
    for (int i = 0; i < gtot; i++) {
        int u = edge[i].u, v = edge[i].v;
        if (belong[u] == belong[v]) continue;
        dpmp[belong[u]].insert(belong[v]);
    }
    cal(belong[getid(1, 0)]);
    printf("%d\n", ans);
    return 0;
}
View Code

 

posted @ 2019-07-14 22:05  ckxkexing  阅读(170)  评论(0编辑  收藏  举报