题意和思路看这篇博客就行了: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. python中set类型总结

    set的创建无非有两种方式: 一 直接使用{}创建新的set并初始化 例如: set1 = {1,2,3,"good news",(1,2,3)} #声明的时候可以包含元组,但不能 ...

  2. Eclipse 快捷键大全(群里共享的,留下来以后兴许会用到)

    Eclipse快捷键大全Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加) Ctrl+Alt+↑ 复制当前行到上一行 ...

  3. 用urliso把linux刻录U盘失败无数次。 用unetbootin试试可以启动的。

    我用的是ubuntu 16.04 lts 画面挺好用的.

  4. Senior Manufacturing Technical Manager

    Job Description As a Manufacturing Technical Manager, you will be responsible for bringing new produ ...

  5. wpf中将string格式的颜色转换成color类型

    wpf中Brushes有很多对应的颜色,先盗张图,每个颜色对于的名称和ARGB值有了,问题是有时候我们取到的颜色是ARGB值,而且是string类型的,该怎么转换成color呢,只有转换成color之 ...

  6. vbox sethduuid

    laozha@abc$ /usr/bin/vboxmanage internalcommands sethduuid /ud1/VBOX/centos7/CentOS7.vdi UUID change ...

  7. JavaWeb框架_Struts2_(四)----->表达式语言OGNL

      2. 表达式语言OGNL 2.1 OGNL简介 OGNL(Object-Graph Navigation Language)对象图导航语言的缩写,OGNL是一种表达式语言(Expression L ...

  8. Python 函数之迭代器和生成器

    1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可 ...

  9. 一段shallowCopy和deepCopy的认识

    :什么是浅拷贝(shallow copy)和深拷贝(deep copy)? A: 浅拷贝就是成员数据之间的一一赋值:把值一一赋给要拷贝的值.但是可能会有这样的情况:对象还包含资源,这里的资源可以值堆资 ...

  10. Northwind 示例数据库

    Northwind 示例数据库 Northwind Traders 示例数据库包含一个名为 Northwind Traders 的虚构公司的销售数据,该公司从事世界各地的特产食品进出口贸易. 下载地址 ...