• Taran 缩点【bzoj1529】[POI2005]ska Piggy banks


    【bzoj1529】[POI2005]ska Piggy banks

    Description

    Byteazar 有 N 个小猪存钱罐. 每个存钱罐只能用钥匙打开或者砸开. Byteazar 已经把每个存钱罐的钥匙放到了某些存钱罐里. Byteazar 现在想买一台汽车于是要把所有的钱都取出来. 他想尽量少的打破存钱罐取出所有的钱,问最少要打破多少个存钱罐.

    Input

    第一行一个整数 N (1 <= N <= 1.000.000) – 表示存钱罐的总数. 接下来每行一个整数,第 i+1行的整数代表第i个存钱罐的钥匙放置的存钱罐编号.

    Output

    一个整数表示最少打破多少个存钱罐.

    Tarjan 很简单的题目。

    但是很毒瘤地卡了空间。

    首先,鉴于每个点只向外连一条有向边,所以不要用常规存边方式存边,直接一个数组就可以了。

    并且在缩完点之后,统计每个强连通分量的出度,出度为零的强联通分量的个数即为答案。

    我还整了个循环数组,卡空间是在是烦。把dfn直接当做vis用了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int wx=1000017;
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    
    int n,x,col,top,ans,tot;
    int num;
    int st[wx],dfn[wx],low[wx],head[wx],belong[wx],a[wx];
    
    void Tarjan(int u){
    	dfn[u]=low[u]=++tot;
    	st[++top]=u;
    	if(!dfn[a[u]]){
    		Tarjan(a[u]);
    		low[u]=min(low[u],low[a[u]]);
    	}
    	else if(!belong[a[u]]){
    		low[u]=min(low[u],dfn[a[u]]);
    	}
    	if(low[u]==dfn[u]){
    		belong[u]=++col;
    		while(st[top]!=u){
    			belong[st[top]]=col;
    			top--;
    		}
    		top--;
    	}
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
    	memset(dfn,0,sizeof dfn);
    	for(int i=1;i<=n;i++){
    		if(belong[i]!=belong[a[i]])dfn[belong[i]]++;
    	}
    	for(int i=1;i<=col;i++)if(!dfn[i])ans++;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    03.redis集群
    02.redis数据同步
    01.redis数据类型
    06.MySQL主从同步
    05.MySQL优化
    04.MySQL慢查询
    lamp服务器站点目录被植入广告代码
    tar命令简单用法
    linux基础优化
    Linux 思想与法则
  • 原文地址:https://www.cnblogs.com/wangxiaodai/p/9761973.html
Copyright © 2020-2023  润新知