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 ", ans); return 0; }