[CodeVS2822]爱在心中 做题笔记

9 篇文章 0 订阅
9 篇文章 0 订阅

题目来源 :http://codevs.cn/problem/2822/

题目描述 Description

“每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动。爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our
Home。”

在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况)。爱是具有传递性的,即如果A爱B,B爱C,则A也爱C。
如果有这样一部分人,他们彼此都相爱,则他们就超越了一切的限制,用集体的爱化身成为一个爱心天使。
现在,我们想知道在这个爱的国度里会出现多少爱心天使。而且,如果某个爱心天使被其他所有人或爱心天使所爱则请输出这个爱心天使是由哪些人构成的,否则输出-1。

输入描述 Input Description

第1行,两个数N、M,代表爱的国度里有N个人,爱的关系有M条。 第2到第M+1行,每行两个数A、B,代表A爱B。

输出描述 Output Description

第1行,一个数,代表爱的国度里有多少爱心天使。
第2行,如果某个爱心天使被其他所有人和爱心天使所爱则请输出这个爱心天使是由哪些人构成的(从小到大排序),否则输出-1。

样例输入 Sample Input

样例输入1:

6 7 1 2 2 3 3 2 4 2 4 5 5 6 6 4

样例输入2:

3 3 1 2 2 1 2 3

样例输出 Sample Output

样例输出1:

2 2 3

样例输出2:

1
-1

数据范围及提示 Data Size & Hint

各个测试点1s

这题是强连通分量缩点。
可以暴力新建一个图,新图就是缩点以后的图,新图中结点为原图单点或一整个强连通分量。
这题第二问有个奇怪的梗。。。可以无视代码中的第二问做法。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int N=50005;
struct ljb {
    int to,next;
}e[N],d[N];
int head[N];
bool vis[N],inq[N];
int q[N],low[N],dfn[N],success=1;
int n,m,top=0,cnt=0,scc=0,belong[N],hav[N],h[N];
int sum=0;
int ans[N],o=0;
void DFS (int a) {
    int now;
    vis[a]=inq[a]=1;
    top++,cnt++;
    q[top]=a;
    low[a]=dfn[a]=cnt;
    for (int i=head[a];i;i=e[i].next) {
        if (!vis[e[i].to]) {
            DFS(e[i].to);
            low[a]=min(low[a],low[e[i].to]);
        }
        else if (inq[e[i].to]) {
            low[a]=min(low[a],dfn[e[i].to]);
        }
    }
    if (dfn[a]==low[a]) {
        scc++;
        while (now!=a) {
            now=q[top--];
            inq[now]=0;
            belong[now]=scc;
            hav[scc]++;
        }
    }
}
void Shrink () {
    cnt=0;
    for (int i=1;i<=n;i++) {
        for (int j=head[i];j;j=e[j].next) {
            if (belong[i]!=belong[e[j].to]) {
                cnt++;
                d[cnt].to=belong[e[j].to];
                d[cnt].next=h[belong[i]];
                h[belong[i]]=cnt;
            }
        }
    }   
}
void Tarjan () {
    for (int i=1;i<=n;i++) {
        if (!vis[i]) DFS(i);
    }
    Shrink();
}
void Findans () {
    for (int i=1;i<=scc;i++) {
        if (hav[i]>1) sum++;
        if (!h[i]) {
            if (o) success=0;
            o=i;
        }
    }
}
bool rule (int x,int y) {
    return x<y;
}
int main () {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        e[i].to=y;
        e[i].next=head[x];
        head[x]=i;
    }
    Tarjan();
    Findans();
    printf("%d\n",sum);
    if (!success) {
        printf("-1");
        return 0;
    }
    else {
        if (hav[o]==1) {
            printf("-1");
            return 0;
        }
        else {
            cnt=0;
            for (int i=1;i<=n;i++)
                if (belong[i]==o) ans[++cnt]=i;
            sort(ans+1,ans+1+cnt,rule);
            for (int i=1;i<=cnt;i++) printf("%d ",ans[i]);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值