题意和思路看这篇博客就行了:https://www.cnblogs.com/cjyyb/p/10507937.html

有个问题需要注意:对于每个scc,只需要考虑进入这个scc的时间即可,其实和从哪个点进没有关系,因为scc内每个点都可以互相到达,所以只需记录时间就囊括了所有的情况,比如时间3从1号点进和时间4从2号点进是等价的,这也是为什么可以随便选择一颗生成树的原因。对于scc的出边,边的长度是val[u] + val[v] - 1,因为假设从scc x的根 到点scc y的点v,时间是val[u] + 1,而scc y的根到v的距离是val[v],所以要求原装态需要减去这个。当然,这个边需要对两个scc的gcd的gcd取模,以判断从这条边到下一条边可以到达的状态。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010; int head[maxn], Next[maxn * 2], ver[maxn * 2], tot;
int heade[maxn], Nexte[maxn * 2 * 50], edgee[maxn * 2 * 50], vere[maxn * 2 * 50], tote, cnt;
int n, m, D, GCD, g[maxn], f[maxn][51], pre[maxn][51], deg[maxn], val[maxn], c[maxn];
int dfn[maxn], low[maxn], num, top, Stack[maxn];
char v[maxn][51];
bool vis[maxn], ins[maxn];
vector<int> scc[maxn];
void add(int x, int y) {
ver[++tot] = y;Next[tot] = head[x];head[x] = tot;
} void adde(int x, int y, int z) {
vere[++tote] = y, edgee[tote] = z, Nexte[tote] = heade[x], heade[x] = tote, deg[y]++;
} void solve(int x, int p) {
val[x] = p, vis[x] = 1;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(c[y] != cnt) continue;
if(!vis[y]) solve(y, p + 1);
else GCD = __gcd(GCD, abs(p + 1 - val[y]));
}
} void tarjan(int x) {
dfn[x] = low[x] = ++num;
Stack[++top] = x, ins[x] = 1;
for (int i = head[x]; i; i = Next[i]) {
if (!dfn[ver[i]]) {
tarjan(ver[i]);
low[x] = min(low[x], low[ver[i]]);
} else if (ins[ver[i]])
low[x] = min(low[x], dfn[ver[i]]);
}
if (dfn[x] == low[x]) {
cnt++;
int y;
do {
y = Stack[top--], ins[y] = 0;
c[y] = cnt, scc[cnt].push_back(y);
} while(x != y);
GCD = D, solve(x, 0); g[cnt] = GCD;
for (int i = 0; i < GCD; i++)
for (int j = 0; j < scc[cnt].size(); j++) {
for (int k = i; k < D; k += GCD)
if(v[scc[cnt][j]][k] == '1') {
v[scc[cnt][j]][i] = '1';
break;
}
}
for (int i = 0; i < GCD; i++)
for (int j = 0; j < scc[cnt].size(); j++) {
if(v[scc[cnt][j]][(val[scc[cnt][j]] + i) % GCD] == '1')
pre[cnt][i]++;
}
}
} void dp(void) {
int ans = 0;
memset(f, -0x3f, sizeof(f));
f[c[1]][0] = pre[c[1]][0];
queue<int> q;
for (int i = 1; i <= cnt; i++) {
if (!deg[i])
q.push(i);
}
while(!q.empty()) {
int x = q.front();
q.pop();
for (int i = heade[x]; i; i = Nexte[i]) {
int y = vere[i];
deg[y]--;
if(deg[y] == 0)
q.push(y);
}
for (int i = heade[x]; i; i = Nexte[i]) {
for (int j = 0; j < D; j++) {
int y = vere[i], z = edgee[i];
f[y][(z + j) % D] = max(f[y][(z + j) % D], f[x][j] + pre[y][(z + j) % g[y]]);
}
}
for (int i = 0; i < D; i++)
ans = max(ans, f[x][i]);
}
printf("%d\n", ans);
} int main() {
int x, y;
scanf("%d%d%d", &n, &m, &D);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &x, &y);
add(x, y);
}
for (int i = 1; i <= n; i++)
scanf("%s", v[i]);
for (int i = 1; i <= n; i++) {
if(!dfn[i])
tarjan(i);
}
for (int j = 1; j <= n; j++)
for (int i = head[j]; i; i = Next[i]) {
int y = ver[i];
if(c[j] == c[y]) continue;
int dd = __gcd(g[c[j]], g[c[y]]);
int d = (val[j] - val[y] + 1 + D) % D;
for (int k = d % dd; k < D; k += dd) {
adde(c[j], c[y], k);
}
}
dp();
}

  

Codeforces 1137C Museums Tour (强连通分量, DP)的更多相关文章

  1. The Largest Clique UVA - 11324( 强连通分量 + dp最长路)

    这题  我刚开始想的是  缩点后  求出入度和出度为0 的点  然后统计个数  用总个数 减去 然而 这样是不可以的  画个图就明白了... 如果  减去度为0的点  那么最后如果出现这样的情况是不可 ...

  2. UVa 11324 The Largest Clique (强连通分量+DP)

    题意:给定一个有向图,求一个最大的结点集,使得任意两个结点,要么 u 能到 v,要么 v 到u. 析:首先,如果是同一个连通分量,那么要么全选,要么全不选,然后我们就可以先把强连通分量先求出来,然后缩 ...

  3. CF1137C Museums Tour(tarjan+DP)

    由于d很小,所以可以把每个点拆成d个点,然后对于边(x,y),连边时连接((x,i),(y,i+1))及((x,d),(y,1)).然后可以对这样连的边跑一遍tarjan缩点.然后直接暴力DP即可.不 ...

  4. 【Codeforces 1137C】Museums Tour

    Codeforces 1137 C 题意:给一个有向图,一周有\(d\)天,每一个点在每一周的某些时刻会开放,现在可以在这个图上从\(1\)号点开始随意地走,问最多能走到多少个开放的点.一个点如果重复 ...

  5. CF1137C Museums Tour(Tarjan,强连通分量)

    好题,神题. 题目链接:CF原网 洛谷 题目大意: 一个国家有 $n$ 个城市,$m$ 条有向道路组成.在这个国家一个星期有 $d$ 天,每个城市有一个博物馆. 有个旅行团在城市 $1$ 出发,当天是 ...

  6. UVA 11324 The Largest Clique(强连通分量+缩点DAG的DP)

    题意:给定一个有向图,求出一个最大的结点集,这个节点集中的随意两个点之间至少一个能到达还有一个点. 思路:假设一个点在这个节点集中,那么它所在的强连通分量中的点一定所有在这个节点集中,反之亦然, 求出 ...

  7. Codeforces Round #244 (Div. 2) C. Checkposts (tarjan 强连通分量)

    题目:http://codeforces.com/problemset/problem/427/C 题意:给你n座城市,m条有向道路,然后有一个机制,你在某一个城市设置检查点,那么被设置的检查点受保护 ...

  8. uva11324 有向图的强连通分量+记忆化dp

    给一张有向图G, 求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足,要么u可以到达v, 要么v可以到达u(u和v相互可达也可以). 因为整张图可能存在环路,所以不好使用dp直接做,先采用 ...

  9. BZOJ 1179 Atm(强连通分量缩点+DP)

    题目说可以通过一条边多次,且点权是非负的,所以如果走到图中的一个强连通分量,那么一定可以拿完这个强连通分量上的money. 所以缩点已经很明显了.缩完点之后图就是一个DAG,对于DAG可以用DP来求出 ...

随机推荐

  1. 51nod 1163 贪心

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1163 1163 最高的奖励 基准时间限制:1 秒 空间限制:131072 ...

  2. JavaScript如何处理解析JSON数据详解

    JSON (JavaScript Object Notation)一种简单的数据格式,比xml更轻巧. JSON 是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON ...

  3. Java tutorial 02

    一.EnumTest.java枚举类型 public class EnumTest { public static void main(String[] args) { Size s=Size.SMA ...

  4. 细说移动前端Android联调

    为什么要联调 A:正在疯狂coding的时候,产品MM过来,焦急的说两周前的一个页面在手机上显示略微错位,但小本上显示正常! B:本着爱折腾的原则,作为大前端,在移动互联网时代的基本技能. 联调的方式 ...

  5. CCEditBox

    EditBox 创建添加 以及 一些函数参数的解析 #include "GUI/CCEditBox/CCEditBox.h" #include "GUI/CCContro ...

  6. AJAX的最小单元

    $(function(){ $('#send').click(function(){ $.ajax({ type: "GET", url: "test.json" ...

  7. POJ - 3150 :Cellular Automaton(特殊的矩阵,降维优化)

    A cellular automaton is a collection of cells on a grid of specified shape that evolves through a nu ...

  8. 【LeetCode】028. Implement strStr()

    Implement strStr(). Return the index of the first occurrence of needle in haystack, or -1 if needle ...

  9. Dos简单命令

    1.cmd命令进入某个目录,具体教程:http://blog.csdn.net/aidenliu/article/details/5390113 (注意的是:切换目录时不能直接cmd D:\Nancy ...

  10. 【HTML代码】访问页面时,拨打页面中的电话号码

      这两天在写HTML页面今天要实现一个手机用户访问页面的时候,如果页面中有电话号码,点击可以打电话或者是发信息,之前没做过今天刚听说感觉很高大上会很难,实际上简单的让我内牛满面啊,,  小婊砸 (* ...