【Codevs】2822 爱在心中 -Tarjan缩点

题解

如果有这样一部分人,他们彼此都相爱,则他们就超越了一切的限制,用集体的爱化身成为一个爱心天使。

什么鬼畜题目QWQ
求爱心天使数,就是tarjan缩点后大小(点数)大于1的scc个数。
可以证明最多存在一个scc使得其他所有scc都可以之间或间接到达该scc,且该scc出度为0(所以显然最多只有一个)
有两种方式判断存在性:

  • 若图中只有一个scc出度为0且该scc的点数大于1,那么就存在。

  • 先将点间连边转化为scc间的连边,枚举点数大于1的scc,若第 i i 个scc出度为0,那么dfs反向连边,若从该scc出发沿反向边可以遍历所有scc,那么就存在,且该scc即为i

每个scc里的点用vector存一下就好了。


代码

1

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=10050;
int n,m,ans[N],bel[N],sum,cnt;
vector<int>hv[N];
int low[N],df[N],dfn,sta[N],top;
int head[N],to[M<<1],nxt[M<<1],tot,g[N][N];

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

inline void dfs(int x)
{
    low[x]=df[x]=++dfn;int i,j;sta[++top]=x;
    for(i=head[x];i;i=nxt[i]){
        j=to[i];
        if(!df[j]){dfs(j);low[x]=min(low[x],low[j]);}
        else if(!bel[j]) low[x]=min(low[x],df[j]);
    }
    if(low[x]==df[x]){
        for(cnt++;sta[top+1]!=x;top--)
        {bel[sta[top]]=cnt;hv[cnt].push_back(sta[top]);}
        if(hv[cnt].size()>1) sum++;
    }

}

int main(){
   int i,j,k,ix,iy,t,res,jud=0;
   scanf("%d%d",&n,&m);
   for(i=1;i<=m;++i){
      scanf("%d%d",&ix,&iy);
      lk(ix,iy);
   }
   for(i=1;i<=n;++i) if(!df[i]) dfs(i);
   for(i=1;i<=n;++i){
     for(j=head[i];j;j=nxt[j]){
        k=to[j];if(bel[k]==bel[i]) continue;
        g[bel[i]][bel[k]]=1;
     }
   }
   printf("%d\n",sum);
   for(i=1;i<=cnt;++i){
     if(hv[i].size()==1) continue;
     for(j=1;j<=cnt;++j)
      if(g[i][j]) break;
     if(j<=cnt) continue;
     res=i;jud++; 
   }
   if(jud!=1) printf("-1\n");
   else{
     tot=hv[res].size();
     for(i=0;i<tot;++i) ans[i]=hv[res][i];
     sort(ans,ans+tot);
     for(i=0;i<tot;++i) printf("%d ",ans[i]);
   }
   return 0;
}

2

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=10050;
int n,m,ans[N],bel[N],vis[N],tim,sum,cnt;
vector<int>hv[N];
int low[N],df[N],dfn,sta[N],ss[N],top;
int head[N],to[M<<1],nxt[M<<1],tot,g[N][N];

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

inline void dfs(int x)
{
    low[x]=df[x]=++dfn;int i,j;sta[++top]=x;
    for(i=head[x];i;i=nxt[i]){
        j=to[i];
        if(!df[j]){dfs(j);low[x]=min(low[x],low[j]);}
        else if(!bel[j]) low[x]=min(low[x],df[j]);
    }
    if(low[x]==df[x]){
        for(cnt++;sta[top+1]!=x;top--)
        {bel[sta[top]]=cnt;hv[cnt].push_back(sta[top]);}
        if(hv[cnt].size()>1) sum++;
    }

}

inline void dfss(int x)
{
    ss[x]=1;vis[x]=tim;
    for(int i=1;i<=cnt;++i)
     if(g[i][x] && vis[i]!=tim){
        dfss(i);ss[x]+=ss[i];
     }
}

int main(){
   int i,j,k,ix,iy,t,res,jud=0;
   scanf("%d%d",&n,&m);
   for(i=1;i<=m;++i){
      scanf("%d%d",&ix,&iy);
      lk(ix,iy);
   }
   for(i=1;i<=n;++i) if(!df[i]) dfs(i);
   for(i=1;i<=n;++i){
     for(j=head[i];j;j=nxt[j]){
        k=to[j];if(bel[k]==bel[i]) continue;
        g[bel[i]][bel[k]]=1;
     }
   }
   printf("%d\n",sum);
   for(i=1;i<=cnt;++i){
     if(hv[i].size()==1) continue;
     for(j=1;j<=cnt;++j)
      if(g[i][j]) break;
     if(j<=cnt) continue;
     tim++;
     dfss(i);if(ss[i]==cnt){
        tot=hv[i].size();
        for(j=0;j<tot;++j) 
         ans[j]=hv[i][j];
        sort(ans,ans+tot);
        for(j=0;j<tot;++j) 
         printf("%d ",ans[j]);
         return 0;
     }
   }
   printf("-1\n");
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值