bzoj1529: [POI2005]ska Piggy banks(tarjan||并查集)

来源:互联网 发布:淘宝团队规模 编辑:程序博客网 时间:2024/05/19 03:22

题目大意:求联通块的数量
显然可以想到tarjan缩点之后统计出度为0的点的数量
但这题会MLE

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=1e6+10;int n,len=0,tot=0,cnt=0,scc=0,top=0,ans=0,last[N],head[N],dfn[N],low[N],ins[N],v[N],bl[N],s[N],fa[N];struct Edge{int to,next;Edge(int to=0,int next=0):to(to),next(next){}}e[N<<1],E[N<<1];void add_edge(int u,int v){e[++len]=Edge(v,last[u]);last[u]=len;}void add_Edge(int u,int v){E[++tot]=Edge(v,head[u]);head[u]=tot;}void tarjan(int x){    int now=0;    dfn[x]=low[x]=++cnt;    s[++top]=x;ins[x]=1;    for(int i=last[x];i;i=e[i].next) {        if(!dfn[e[i].to]){            tarjan(e[i].to);            low[x]=min(low[x],low[e[i].to]);        }else if(ins[e[i].to])low[x]=min(low[x],dfn[e[i].to]);    }    if(dfn[x]==low[x]) {        ++scc;        while(now!=x) {            now=s[top--];ins[now]=0;            bl[now]=scc;            v[scc]++;        }    }}void rebuild(){    tot=0;    for(int i=1;i<=n;i++)         for(int j=last[i];j;j=e[i].next)             if(bl[i]!=bl[e[i].to])                add_Edge(bl[i],bl[e[j].to]);}void solve(){    for(int i=1;i<=scc;i++) {        if(!head[i]) ans++;    }}int main(){    scanf("%d",&n);    for(int id,i=1;i<=n;i++) {        scanf("%d",&id);        add_edge(id,i);    }       fo(i,1,n)if(!dfn[i])tarjan(i);    rebuild();    solve();    printf("%d\n",ans-1);    return 0;}

对于联通块还有一种数据结构可以维护:并查集
最后统计答案时,就是每个点的所属有多少个不同编号,或者是有多少点的编号不变(两者是等价的,但后者快一点)(1720ms,1940ms)

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=1e6+10;int fa[N],n,len=0,vis[N],ans=0;struct Edge{int from,to;Edge(int from=0,int to=0):from(from),to(to){}}e[N];void add_edge(int u,int v){e[++len]=Edge(u,v);}int Fd(int x){return x==fa[x]?fa[x]:fa[x]=Fd(fa[x]);}void solve(){    fo(i,1,n) fa[i]=i;    for(int i=1;i<=n;i++) {        int idx=Fd(e[i].from),idy=Fd(e[i].to);        if(idx==idy)continue;        fa[idx]=idy;    }    fo(i,1,n) if(!vis[Fd(i)]){ans++;vis[Fd(i)]=1;}//或者    fo(i,1,n) if(fa[i]==i) ans++;}int main(){    scanf("%d",&n);    for(int id,i=1;i<=n;i++) {        scanf("%d",&id);        add_edge(id,i);    }    solve();    printf("%d\n",ans);    return 0;}
原创粉丝点击