BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划
Posted 繁凡さん
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划相关的知识,希望对你有一定的参考价值。
整理的算法模板合集: ACM模板
实际上是一个全新的精炼模板整合计划
Weblink
https://hydro.ac/d/bzoj/p/1589
Problem
每年万圣节,威斯康星的奶牛们都要打扮一番,出门在农场的 n n n 个牛棚里转悠,来采集糖果。她们每走到一个未曾经过的牛棚,就会采集这个棚里的 1 1 1 颗糖果。农场不大,所以约翰要想尽法子让奶牛们得到快乐。
他给每一个牛棚设置了一个「后继牛棚」。牛棚 i i i 的后继牛棚是 x i x_i xi 。他告诉奶牛们,她们到了一个牛棚之后,只要再往后继牛棚走去,就可以搜集到很多糖果。事实上这是一种有点欺骗意味的手段,来节约他的糖果,因为每一只奶牛最多只能在同一个牛棚中采集到的一个糖果。第 i i i 只奶牛从牛棚 i i i 开始她的旅程。请你计算,每一只奶牛可以采集到多少糖果。
1 ≤ n ≤ 1 0 5 1≤n≤10^5 1≤n≤105
Solution
狡猾的约翰设计了一个圈套,只要奶牛走到一个环里,就不会再走出去了,而这头奶牛能获得的糖果数量显然就是这个环的 s i z e \\mathrm{size} size。
对于给定的这个有向图,每个点只有两种情况:
- 要么在环中,答案显然是环的 s i z e \\mathrm{size} size 。
- 要么通过一条链与环相接,答案显然是点到环的最短距离 + 环的 s i z e \\mathrm{size} size。
为了计算点到环的最短距离,我们先对图进行缩点并记录各个环的大小 ,然后对于新图跑一个记忆化搜索统计答案即可,当然直接跑也行()。
Hint
注意特判环大小为 1 1 1 也即自环的情况。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 6, maxm = maxn << 1 | 7;
int n, m, s, t;
int head[maxn], ver[maxm], edge[maxm], nex[maxn], tot;
bool vis[maxn];
bool ins[maxn];
int dfn[maxn], low[maxn], tim;
int stk[maxn], top;
int scc_cnt, scc_id[maxn], scc_size[maxn];
vector <int> scc[maxn];
int nex_node[maxn];
int ans[maxn];
#define input(x) input(x);
#define print(x) print(x);
template <typename T> inline T input(T &x)
{
x = 0;
T f = 0;
char ch = getchar();
while(!isdigit(ch)) {f |= (ch == '-'), ch = getchar();}
while(isdigit(ch)) {x = x * 10 + ch - 48, ch = getchar();}
if(f) x = -x;
return x;
}
template <typename T> inline void print(T x)
{
if(x < 0) putchar('-');
if(x > 9)
print(x / 10);
putchar(x % 10 + 48);
}
void add(int x, int y)
{
ver[tot] = y;
nex[tot] = head[x];
head[x] = tot ++ ;
}
void tarjan(int x)
{
dfn[x] = ++ tim;
low[x] = tim;
ins[x] = true;
stk[ ++ top] = x;
for (int i = head[x]; ~i; i = nex[i]) {
int y = ver[i];
if(dfn[y] == 0) {
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if(ins[x])
low[x] = min(low[x], dfn[y]);
}
if(dfn[x] == low[x]) {
scc_cnt ++ ;
int y;
do {
y = stk[top -- ];
scc_id[y] = scc_cnt;
scc_size[scc_cnt] ++ ;
scc[scc_cnt].emplace_back(y);
}while(x != y);
}
}
void dfs(int x, int y, int step)
{
if(ans[y] != 0) {
ans[x] = ans[y] + step;
return ;
}
dfs(x, nex_node[y], step + 1);
}
void pre_work()
{
tot = 0;
memset(head, -1, sizeof head);
memset(dfn, 0, sizeof dfn);
memset(scc_size, 0, sizeof scc_size);
}
int main()
{
pre_work();
n = input(n)
for (int i = 1; i <= n; ++ i) {
int x;
x = input(x)
nex_node[i] = x;
add(i, nex_node[i]);
if(i == nex_node[i])
ans[i] = 1;
}
for (int i = 1; i <= n; ++ i)
if(dfn[i] == 0)
tarjan(i);
for (int i = 0; i < tot; ++ i) {
int x = ver[i ^ 1], y = ver[i];
if(scc_id[x] == scc_id[y]) continue;
add(scc_id[x], scc_id[y]);
}
for (int i = 1; i <= n; ++ i)
if(scc_size[scc_id[i]] != 1)
ans[i] = scc_size[scc_id[i]];
for (int i = 1; i <= n; ++ i)
if(ans[i] == 0)
dfs(i, nex_node[i], 1);
for (int i = 1; i <= n; ++ i) {
print(ans[i])
puts("");
}
return 0;
}
以上是关于BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划的主要内容,如果未能解决你的问题,请参考以下文章
bzoj1589 [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果
bzoj 1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果
BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划
BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划
BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划
bzoj 1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果tarjan+记忆化搜索