[USACO08DEC] Trick or Treat on the Farm

題目描述

每一年萬聖節,威斯康星的奶牛們都要打扮一番,出門在農場的N個牛棚裏轉 悠,來採集糖果.她們每走到一個不曾通過的牛棚,就會採集這個棚裏的1顆糖果.ios

農場不大,因此約翰要想盡法子讓奶牛們獲得快樂.他給每個牛棚設置了一個「後繼牛 棚」.牛棚i的後繼牛棚是next_i 他告訴奶牛們,她們到了一個牛棚以後,只要再日後繼牛棚走去, 就能夠蒐集到不少糖果.事實上這是一種有點欺騙意味的手段,來節約他的糖果.數組

第i只奶牛從牛棚i開始她的旅程.請你計算,每一隻奶牛能夠採集到多少糖果.spa

輸入輸出格式

輸入格式:code

  • Line 1: A single integer: Nblog

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

輸出格式:ci

  • 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.it

  • Stall 1 directs the cow back to stall 1.io

  • Stall 2 directs the cow to stall 3ast

  • Stall 3 directs the cow to stall 2class

  • 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 }
相關文章
相關標籤/搜索