题意和思路看这篇博客就行了: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. 《Advanced Bash-scripting Guide》学习(八):从一个目录移动整个目录树到另一个目录

    本文所选的例子来自于<Advanced Bash-scripting Gudie>一书,译者 杨春敏 黄毅 ABS书上的例子: 从一个目录移动整个目录树到另一个目录 #!/bin/bash ...

  2. Eclipse插件开发_学习_00_资源帖

    一.官方资料 1.eclipse api 2.GEF Developer's Guide 二. 精选资料 1.开发 Eclipse 插件 2.Eclipse, RCP, Plugin and OSGi ...

  3. linux shell 学习笔记--比较操作

    整数比较 -eq 等于,如:if [ "$a" -eq "$b" ] -ne 不等于,如:if [ "$a" -ne "$b&qu ...

  4. 开发mis系统用到的技术

    1. b/s架构:就broser/server,浏览器/服务器的说法.服务器端要运行tomcat,提供链接数据库服务供java代码读写数据,这个可以在eclipse中配置运行.浏览器则解释jsp或ht ...

  5. centos安装教程

      centos7和6.x有很大的差别,在第一次安装的时候遇到了很多坑,一共安装了三次才成功 如果是用window自带的Hyper-v装centos时 安装包在\\10.10.10.1\ShareDo ...

  6. 隐藏select中的“请选择”项

    <select> <option value="" style="display: none">请选择</option> & ...

  7. PCM音量控制

    http://blog.jianchihu.net/pcm-volume-control.html 一.声音的相关概念 声音是介质振动在听觉系统中产生的反应.声音总可以被分解为不同频率不同强度正弦波的 ...

  8. 超时 CS-8610 中性笔

    超时 CS-8610 中性笔 最初觉得这款笔很简单,而且还认为有点丑,因为笔头比较短. 比较特别提这款中性笔比一般的中性笔要粗一点. 使用后才发现比其它的中性笔好用,因为笔杆粗,手感好,笔杆上并没有特 ...

  9. Azure上采用Powershell从已有的VHD创建VM

    刚刚的一篇Blog采用Json Template的方式从已有的VHD创建了一台新的VM.由于Json Template封装的比较好,可以改的内容不多. 下面将介绍通过用Powershell来从已有的V ...

  10. check: 获得所有呗选中的checked标签的元素值 mapArrayElement(arrEles)

    首先引用: <script src="../js/myjs/mapArrayElement.js"></script> 然后在<javascript& ...