Fork me on GitHub

1626 爱在心中

vijos

描述

“每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动。爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home。”
在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况)。爱是具有传递性的,即如果A爱B,B爱C,则A也爱C。
如果有这样一部分人,他们彼此都相爱,则他们就超越了一切的限制,用集体的爱化身成为一个爱心天使。
现在,我们想知道在这个爱的国度里会出现多少爱心天使。而且,如果某个爱心天使被其他所有人或爱心天使所爱则请输出这个爱心天使是由哪些人构成的,否则输出-1。
格式

输入格式

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

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

样例输入1

6 7
1 2
2 3
3 2
4 2
4 5
5 6
6 4
样例输出1

2
2 3
样例2

样例输入2

3 3
1 2
2 1
2 3
样例输出2

1
-1
限制

各个测试点1s
提示

对于40%的数据 N<=10 M<=100
对于80%的数据 N<=100 M<=1000
对于100%的数据 N<=1000 M<=10000
来源

Cai0715 原创
NOIP 2009·Dream Team 模拟赛 第一期 第四题

分析:
此题无疑用强连通分量;( 注意规模为一的强连通分量不算爱心天使 , 在出栈时只出一个点就不算)
难点就在寻找被所有人爱的爱心天使;
处理方法:在每个强连通分量中,如果找到有指出到强连通分量外的点,则不会成为被所有人或all爱心天
使爱的,break,如此找,如果找到两个,输出-1;
如果找到的唯一强连通分量内只有一个点,输出-1;

代码

#include<iostream>
#include<cstdio> 
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
int st[1009],n,m;
int head[1009],num[10009],net[10009],cnt=0,top=0,ans=0;
int color_num=0,dfs_num=0,dfn[1009],color[1009],low[1009];
bool vis[1009];
bool f[1009];
void Tarjan(int x)
{
    st[++top]=x;
    dfn[x]=++dfs_num;
    low[x]=dfs_num;
    vis[x]=true;

    for(int i=head[x];i;i=net[i])
    {
        int k=num[i];
        if(!dfn[k])
        {
            Tarjan(k);
            low[x]=min(low[x],low[k]);
        }
        else
        if(vis[k]) low[x]=min(low[x],dfn[k]);
    }

    if(low[x]==dfn[x])
    {
        vis[x]=false;
        color[x]=++color_num;
        int t=0;
        while(st[top]!=x)
        {
            vis[st[top]]=false;
            color[st[top]]=color_num;
            top--;
            t++;
        }
        top--;
        if(t>=1) ans++;
        else f[color_num]=true;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y); 
        cnt++;
        num[cnt]=y;
        net[cnt]=head[x];
        head[x]=cnt;
    }

    for(int i=1;i<=n;i++)
    if(!dfn[i]) Tarjan(i);

    printf("%d\n",ans);

    int co=0,cnt2=0;
    int tot=0,ansco;

    for(co=1;co<=color_num;co++)//扫描强连通分量 
    {
        cnt2=0;
        bool pp=false;
        for(int x=1;x<=n;x++)
        {

            if(color[x]==co) st[++cnt2]=x;
            for(int i=head[x];i;i=net[i])
            {
                if(color[num[i]]==co)
                st[++cnt2]=num[i];//记录 
            }
            for(int i=1;i<=cnt2;i++)
            {
                for(int j=head[st[i]];j;j=net[j])
                {
                    if(color[num[j]]!=co)
                    {
                        pp=true;//有指出 强连通分量的点,此强连通分量不可能成为 ’ super爱心天使 ‘ break 
                        break;
                    }
                }
                if(pp) break;
            }

        } 
        if(pp) continue;//跳出此个强连通分量 
        else {
            tot++;
            if(tot>1) {//找到一个以上出度为0的 强联通分量 (爱心天使) ,无解 
                printf("-1\n");
                return 0;
            }
            else
            ansco=co;
        }
    }

    if(!f[ansco])//找到的是不是单点 
    {
        for(int i=1;i<=n;i++)
         if(color[i]==ansco)
          printf("%d ",i);
    }

    else printf("-1\n");    

    return 0;

} 
posted @ 2017-03-01 15:49  primes  阅读(310)  评论(0编辑  收藏  举报