• [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
    ",cir[i]);
    76     for (int i=1; i<=n; i++) printf("%d
    ",dfs(i));//记忆化搜索
    77     return 0;
    78 }
  • 相关阅读:
    css3动画之1--animation小例子
    炎炎夏日,走入美妙的前端设计案例
    模拟腾讯、携程、百度音乐 移动端图片切换第一版
    仿QQ空间长图效果简易版--母亲节感恩
    001-搭建框架
    javascript事件绑定1-模拟jquery可爱的东西
    图片尺寸
    mvc3结合spring.net-依赖注入
    *创建索引初步
    Lucene的分词_中文分词器介绍
  • 原文地址:https://www.cnblogs.com/zoewilly/p/6018132.html
Copyright © 2020-2023  润新知