Codeforces 1137C Museums Tour (强连通分量, DP)
题意和思路看这篇博客就行了: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)的更多相关文章
- The Largest Clique UVA - 11324( 强连通分量 + dp最长路)
这题 我刚开始想的是 缩点后 求出入度和出度为0 的点 然后统计个数 用总个数 减去 然而 这样是不可以的 画个图就明白了... 如果 减去度为0的点 那么最后如果出现这样的情况是不可 ...
- UVa 11324 The Largest Clique (强连通分量+DP)
题意:给定一个有向图,求一个最大的结点集,使得任意两个结点,要么 u 能到 v,要么 v 到u. 析:首先,如果是同一个连通分量,那么要么全选,要么全不选,然后我们就可以先把强连通分量先求出来,然后缩 ...
- CF1137C Museums Tour(tarjan+DP)
由于d很小,所以可以把每个点拆成d个点,然后对于边(x,y),连边时连接((x,i),(y,i+1))及((x,d),(y,1)).然后可以对这样连的边跑一遍tarjan缩点.然后直接暴力DP即可.不 ...
- 【Codeforces 1137C】Museums Tour
Codeforces 1137 C 题意:给一个有向图,一周有\(d\)天,每一个点在每一周的某些时刻会开放,现在可以在这个图上从\(1\)号点开始随意地走,问最多能走到多少个开放的点.一个点如果重复 ...
- CF1137C Museums Tour(Tarjan,强连通分量)
好题,神题. 题目链接:CF原网 洛谷 题目大意: 一个国家有 $n$ 个城市,$m$ 条有向道路组成.在这个国家一个星期有 $d$ 天,每个城市有一个博物馆. 有个旅行团在城市 $1$ 出发,当天是 ...
- UVA 11324 The Largest Clique(强连通分量+缩点DAG的DP)
题意:给定一个有向图,求出一个最大的结点集,这个节点集中的随意两个点之间至少一个能到达还有一个点. 思路:假设一个点在这个节点集中,那么它所在的强连通分量中的点一定所有在这个节点集中,反之亦然, 求出 ...
- Codeforces Round #244 (Div. 2) C. Checkposts (tarjan 强连通分量)
题目:http://codeforces.com/problemset/problem/427/C 题意:给你n座城市,m条有向道路,然后有一个机制,你在某一个城市设置检查点,那么被设置的检查点受保护 ...
- uva11324 有向图的强连通分量+记忆化dp
给一张有向图G, 求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足,要么u可以到达v, 要么v可以到达u(u和v相互可达也可以). 因为整张图可能存在环路,所以不好使用dp直接做,先采用 ...
- BZOJ 1179 Atm(强连通分量缩点+DP)
题目说可以通过一条边多次,且点权是非负的,所以如果走到图中的一个强连通分量,那么一定可以拿完这个强连通分量上的money. 所以缩点已经很明显了.缩完点之后图就是一个DAG,对于DAG可以用DP来求出 ...
随机推荐
- java 文件类 null与exists()是不一样的
java 文件类 null与exists()是不一样的File imageFile0A=null; (imageFile0A==null)与!imageFile0A.exists() 不等价! 一个文 ...
- New Concept English three (58)
30w/m 76 errors The old lady was glad to be back at the block of flats where she lived. Her shopping ...
- mysql前缀索引的应用
在mysql中有时需要索引的列很长,如果直接应用索引会造成索引过大的问题.因此我们可以取其中一部分字段来做索引,例: 添加索引:alter table * add key (field(3)); ...
- python lambda 用途
可以让一个带参数函数,传递并以无参调用 def test(a): print a a=test # #a() a=897987 fun=lambda : test(a) fun()
- HDU - 5307 :He is Flying (分治+FFT)(非正解)
JRY wants to drag racing along a long road. There are nn sections on the road, the ii-th section has ...
- BZOJ4861 [Beijing2017]魔法咒语
题意 Chandra 是一个魔法天才.从一岁时接受火之教会洗礼之后, Chandra 就显示出对火元素无与伦比的亲和力,轻而易举地学会种种晦涩难解的法术.这也多亏 Chandra 有着常人难以企及的语 ...
- 类和对象(9)—— new和delete
对象动态建立和释放 new 和delete 在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除.在C语言中是利用库函数malloc和free来分配和撤销内存空间的.C ...
- unitychan-crs 头发随动脚本
// //SpringCollider for unity-chan! // //Original Script is here: //ricopin / SpringCollider.cs //Ro ...
- 使用bat文件实现批量重命名功能
在生活中我们总会碰到对大量文件进行重命名操作,这时如果一个一个的,选取文件→右键→重命名→选取文件,这样操作势必会浪费大量时间. 现在小编就告诉大家一个使用bat文件(命令行)的方法,快速对文件进行重 ...
- 【转】Java内存与垃圾回收调优
要了解Java垃圾收集机制,先理解JVM内存模式是非常重要的.今天我们将会了解JVM内存的各个部分.如何监控以及垃圾收集调优. Java(JVM)内存模型 正如你从上面的图片看到的,JVM内存被分成多 ...