[CF1137]Museums Tour

\(\text{Description:}\)

一个国家有 \(n\) 个城市,\(m\) 条有向道路组成。在这个国家一个星期有 \(d\) 天,每个城市有一个博物馆。

有个旅行团在城市 \(1\) 出发,当天是星期一。每天早上,如果这个城市的博物馆开了,那么可以去这个博物馆参观。每天晚上,旅行团可以选择沿一条出边前往下一个城市,或者结束旅行。一个城市可以经过多次。

请问旅行团最多能参观多少个博物馆。一个博物馆参观了多次,只计算一次。

\(1\le n, m\le 10^5,1\le d\le 50\)

\({\rm Solution:}\)

由于\({\rm d}\)只有\({\rm 50}\)天,所以考虑分层图,分成\({\rm 50}\)层,每个点只有在它开放的那个时间(那一层)有\({\rm 1}\)的权值,其余权值均为\({\rm 0}\),对于原图的一条边 \({\rm E(x, y)}\), 在分层图中 \({\rm E(x_i, y_{i+1}), (1\le i\le d-1)}\)\({\rm E(x_d, y_1)}\)

然后缩点成\({\rm DAG}\), \({\rm DP}\) 即可。

注意一个细节就是如果很多个点 \({\rm x_i}\) 在同一个强连通分量中,权值只加一次。

#include <vector>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <assert.h>
#include <algorithm>

using namespace std;

#define LL long long
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define GO debug("GO\n")
#define rep(i, a, b) for (register int (i) = (a); (i) <= (b); ++ (i))

const int INF = 0x3f3f3f3f;
const char Enter = '\n';
inline int rint() {
  register int x = 0, f = 1; register char c;
  while (!isdigit(c = getchar())) if (c == '-') f = -1;
  while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getchar()));
  return x * f;
}
struct Stream {
    Stream operator>> (int &x)
    { x = rint(); return *this; }
    Stream operator<< (int x)
    { printf("%d", x); return *this; }
    Stream operator<< (char ch)
    { putchar(ch); return *this; }
} xin, xout;

template<typename T> inline void chkmin(T &a, T b) { a > b ? a = b : 0; }
template<typename T> inline void chkmax(T &a, T b) { a < b ? a = b : 0; }

const int N = 1e5 + 10;

struct Edge {
    int v, nxt;
} E[N * 51];
int tot, head[N * 51];
vector<int> G[N * 51];

inline void add(int u, int v) 
{ E[++tot] = (Edge){v, head[u]}; head[u] = tot; }

int n, m, d, val[N * 50], col[N * 50], dfn[N * 50], low[N * 50], have[N * 50];

stack<int> stk;
void tarjan(int u) {
    dfn[u] = low[u] = ++dfn[0];
    stk.push(u);
    for (register int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (!dfn[v]) tarjan(v), chkmin(low[u], low[v]);
        else if (!col[v]) chkmin(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        col[0]++;
        int v;
        do {
            v = stk.top(); stk.pop();
            col[v] = col[0];
        } while (v != u);
    }
}

int dp[N * 50];

int DFS(int u) {
    if (dp[u]) return dp[u];
    for (int i = 0; i < G[u].size(); ++  i) {
        int v = G[u][i];
        chkmax(dp[u], DFS(v));
    }
    return dp[u] += val[u];
}


int main() {
    xin >> n >> m >> d;// fast_read
    int u, v;
    rep(i, 1, m) {
        xin >> u >> v;
        rep(j, 1, d - 1) add(u + (j - 1) * n, v + j * n);
        add(u + (d - 1) * n, v);
    }
    rep(i, 1, d * n) if (!dfn[i]) tarjan(i);

    rep(i, 1, n * d) for (register int j = head[i]; j; j = E[j].nxt) if (col[E[j].v] != col[i]) 
                G[col[i]].push_back(col[E[j].v]);

    rep(i, 1, n) {
        static char str[N]; scanf("%s", str + 1);
        rep(j, 1, d) {
            if (str[j] == '1' and have[col[i + (j - 1) * n]] != i) 
                have[col[i + (j - 1) * n]] = i, val[col[i + (j - 1) * n]]++;
        }
    }

    xout << DFS(col[1]) << Enter;

    return 0;
}
posted @ 2019-04-01 16:33  茶Tea  阅读(162)  评论(0编辑  收藏  举报