1. 程式人生 > >洛谷 P2921 [USACO08DEC]在農場萬聖節Trick or Treat on the Farm

洛谷 P2921 [USACO08DEC]在農場萬聖節Trick or Treat on the Farm

names sco -s fine -c farm 直接 -a rect

P2921 [USACO08DEC]在農場萬聖節Trick or Treat on the Farm

題目描述

Every year in Wisconsin the cows celebrate the USA autumn holiday of Halloween by dressing up in costumes and collecting candy that Farmer John leaves in the N (1 <= N <= 100,000) stalls conveniently numbered 1..N.

Because the barn is not so large, FJ makes sure the cows extend their fun by specifying a traversal route the cows must follow. To implement this scheme for traveling back and forth through the barn, FJ has posted a ‘next stall number‘ next_i (1 <= next_i <= N) on stall i that tells the cows which stall to visit next; the cows thus might travel the length of the barn many times in order to collect their candy.

FJ mandates that cow i should start collecting candy at stall i. A cow stops her candy collection if she arrives back at any stall she has already visited.

Calculate the number of unique stalls each cow visits before being forced to stop her candy collection.

POINTS: 100

每年萬聖節,威斯康星的奶牛們都要打扮一番,出門在農場的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.

思路:tarjin縮點+dfs。

一開始是直接搜索:

技術分享圖片
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100010
using namespace std;
map<int,int>ma[MAXN];
int n,tot,tot1,tim,top,num,sumcol;
int to[MAXN],net[MAXN],head[MAXN];
int to1[MAXN],net1[MAXN],head1[MAXN];
int stack[MAXN],visstack[MAXN],ans[MAXN];
int low[MAXN],dfn[MAXN],vis[MAXN],col[MAXN],sum[MAXN];
void add(int u,int v){
    to[++tot]=v;net[tot]=head[u];head[u]=tot;
}
void add1(int u,int v){
    to1[++tot1]=v;net1[tot1]=head1[u];head1[u]=tot1;
}
void tarjin(int now){
    low[now]=dfn[now]=++tim;
    vis[now]=1;visstack[now]=1;
    stack[++top]=now;
    for(int i=head[now];i;i=net[i])
        if(visstack[to[i]])
            low[now]=min(low[now],dfn[to[i]]);
        else if(!vis[to[i]]){
            tarjin(to[i]);
            low[now]=min(low[now],low[to[i]]);
        }
    if(low[now]==dfn[now]){
        col[now]=++sumcol;
        while(stack[top]!=now){
            col[stack[top]]=sumcol;
            visstack[stack[top]]=0;
            sum[sumcol]++;top--;
        }
        visstack[now]=0;top--;sum[sumcol]++;
    }
}
void dfs(int now){
    num+=sum[now];
    for(int i=head1[now];i;i=net1[i])
        dfs(to1[i]);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        add(i,x);
    }
    for(int i=1;i<=n;i++)
        if(!vis[i])    tarjin(i);
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=net[j])
            if(col[i]!=col[to[j]])
                if(ma[col[i]].find(col[to[j]])==ma[col[i]].end()){
                    ma[col[i]][col[to[j]]]=1;
                    add1(col[i],col[to[j]]);
                }
    for(int i=1;i<=sumcol;i++){ num=0;dfs(i);ans[i]=num; }
    for(int i=1;i<=n;i++)    cout<<ans[col[i]]<<endl;
}
40分暴力

後來改成記憶化搜索就AC了

#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100010
using namespace std;
map<int,int>ma[MAXN];
int n,tot,tot1,tim,top,num,sumcol;
int to[MAXN],net[MAXN],head[MAXN];
int to1[MAXN],net1[MAXN],head1[MAXN];
int stack[MAXN],visstack[MAXN],ans[MAXN];
int low[MAXN],dfn[MAXN],vis[MAXN],col[MAXN],sum[MAXN];
void add(int u,int v){
    to[++tot]=v;net[tot]=head[u];head[u]=tot;
}
void add1(int u,int v){
    to1[++tot1]=v;net1[tot1]=head1[u];head1[u]=tot1;
}
void tarjin(int now){
    low[now]=dfn[now]=++tim;
    vis[now]=1;visstack[now]=1;
    stack[++top]=now;
    for(int i=head[now];i;i=net[i])
        if(visstack[to[i]])
            low[now]=min(low[now],dfn[to[i]]);
        else if(!vis[to[i]]){
            tarjin(to[i]);
            low[now]=min(low[now],low[to[i]]);
        }
    if(low[now]==dfn[now]){
        col[now]=++sumcol;
        while(stack[top]!=now){
            col[stack[top]]=sumcol;
            visstack[stack[top]]=0;
            top--;sum[sumcol]++;
        }
        visstack[now]=0;top--;sum[sumcol]++;
    }
}
void dfs(int now){
    if(ans[now])    return ;
    ans[now]+=sum[now];
    for(int i=head1[now];i;i=net1[i]){
        dfs(to1[i]);
        ans[now]+=ans[to1[i]];
    }   
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        add(i,x);
    }
    for(int i=1;i<=n;i++)
        if(!vis[i])    tarjin(i);
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=net[j])
            if(col[i]!=col[to[j]])
                if(ma[col[i]].find(col[to[j]])==ma[col[i]].end()){
                    ma[col[i]][col[to[j]]]=1;
                    add1(col[i],col[to[j]]);
                }
    for(int i=1;i<=n;i++)    dfs(col[i]);
    for(int i=1;i<=n;i++)    cout<<ans[col[i]]<<endl;
}

洛谷 P2921 [USACO08DEC]在農場萬聖節Trick or Treat on the Farm