[USACO08DEC] Trick or Treat on the Farm

Posted Zoewilly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[USACO08DEC] Trick or Treat on the Farm相关的知识,希望对你有一定的参考价值。

题目描述

每年万圣节,威斯康星的奶牛们都要打扮一番,出门在农场的N个牛棚里转 悠,来采集糖果.她们每走到一个未曾经过的牛棚,就会采集这个棚里的1颗糖果.

农场不大,所以约翰要想尽法子让奶牛们得到快乐.他给每一个牛棚设置了一个“后继牛 棚”.牛棚i的后继牛棚是next_i 他告诉奶牛们,她们到了一个牛棚之后,只要再往后继牛棚走去, 就可以搜集到很多糖果.事实上这是一种有点欺骗意味的手段,来节约他的糖果.

第i只奶牛从牛棚i开始她的旅程.请你计算,每一只奶牛可以采集到多少糖果.

输入输出格式

输入格式:

  • Line 1: A single integer: N

  • Lines 2..N+1: Line i+1 contains a single integer: next_i

输出格式:

  • Lines 1..N: Line i contains a single integer that is the total number of unique stalls visited by cow i before she returns to a stall she has previously visited.

输入输出样例

输入样例#1:
4 
1 
3 
2 
3 
输出样例#1:
1 
2 
2 
3 

说明

Four stalls.

  • Stall 1 directs the cow back to stall 1.

  • Stall 2 directs the cow to stall 3

  • Stall 3 directs the cow to stall 2

  • Stall 4 directs the cow to stall 3

Cow 1: Start at 1, next is 1. Total stalls visited: 1.

Cow 2: Start at 2, next is 3, next is 2. Total stalls visited: 2. Cow 3: Start at 3, next is 2, next is 3. Total stalls visited: 2. Cow 4: Start at 4, next is 3, next is 2, next is 3. Total stalls visited: 3.

 

 

 

  • 本题n<=100000,首先考虑记忆化搜索,因为纯搜索在某些极端情况一定会被卡(n^2)。
  • 但是记忆化搜索怎么实现呢?
  • 通过观察样例发现,本题存在环。
  • tarjan缩点+记忆化搜索。(大神说不用tarjan)
  • 所有环上的点的答案即为该环的长度,其余的点呢?因为其他的点都是指向某个环的,所以记忆化搜索即可(dp)。
  • 期望得分100分。

 

 

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #define time dscada
 5 using namespace std;
 6 
 7 int n,l,cnt,top,next[100050],summ[100050],pre[100050],time,last[100050],other[100050],f[100050],dfn[100050],low[100050],stack[100050],huan[100050];
 8 bool cir[100050],vis[100050];
 9 
10 void add(int u,int v) {
11     pre[++l]=last[u];
12     last[u]=l;
13     other[l]=v;
14 }
15 
16 void tarjan(int x) {
17     dfn[x]=low[x]=++time;
18     stack[++top]=x;
19     vis[x]=1;
20     for (int p=last[x]; p; p=pre[p]) {
21         int q=other[p];
22         if (!dfn[q]) {
23             tarjan(q);
24             low[x]=min(low[x],low[q]);
25         } else if (vis[q]) low[x]=min(low[x],dfn[q]);
26     }
27     if (dfn[x]==low[x]) {
28         int sum=0;
29         cnt++;
30         int now=stack[top--];
31         cir[now]=1;
32         vis[now]=0;
33         huan[now]=cnt;
34         sum++;
35         while (now!=x) {
36             now=stack[top--];
37             cir[now]=1;
38             vis[now]=0;
39             huan[now]=cnt;
40             sum++;
41         }
42         summ[cnt]=sum;
43     }
44 }
45 
46 int dfs(int x) {
47     if (f[x]) return f[x];
48     if (next[x]==x) {
49         f[x]=1;
50         return f[x];
51     }
52     if (cir[x]) {
53         f[x]=summ[huan[x]];
54         return f[x];
55     }
56     if (cir[next[x]]) {
57         f[x]=summ[huan[next[x]]]+1;
58         return f[x];
59     }
60     f[x]=dfs(next[x])+1;
61     return f[x];
62 }
63 
64 int main() {
65     scanf("%d",&n);
66     for (int i=1; i<=n; i++) {
67         int x;
68         scanf("%d",&x);
69         next[i]=x;
70         if (x!=i) add(i,x);//其实这里没有必要建边,用next数组即可。
71     }
72     for (int i=1; i<=n; i++) 
73         if (!dfn[i]) tarjan(i);//tarjan缩点
74     for (int i=1; i<=n; i++) if (summ[huan[i]]==1) cir[i]=0;
75     //for (int i=1; i<=n; i++) printf("%d\n",cir[i]);
76     for (int i=1; i<=n; i++) printf("%d\n",dfs(i));//记忆化搜索
77     return 0;
78 }

 

以上是关于[USACO08DEC] Trick or Treat on the Farm的主要内容,如果未能解决你的问题,请参考以下文章

题解[USACO08DEC-Gold] Trick or Treat on the Farm

[USACO08DEC]Trick or Treat on the Farm

[USACO08DEC] Trick or Treat on the Farm

P2921 [USACO08DEC]Trick or Treat on the Farm G(Targan)

[USACO08DEC]在农场万圣节Trick or Treat on the Farm

P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm(Tarjan+记忆化)