爱在心中

题目描述 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


思路

第一问比较简单,在tarjan的同时统计出来强连通分量的总数belongx,然后减去仅有一个点的强连通分量个数,即第一问答案;

对于第二问,首先注意如果有多个天使符合这个条件,那么也要输出-1,否则会WA一个点,还好WA点不多;


对于一个符合题意的强连通分量,所有点都可以到达它,但是它出度为0,因为一旦有一个出度,就说明有一个点所连的边能从这个天使中出去,但是会不到这个天使(因为已经缩完点了)。所以扫描所有强连通分量,然后排序输出那个出度为0的天使即可。

代码

type
  point=^rec;
  rec=record
   e:longint;
   s:point;
   end;
  ar=array[0..100]of longint;
var dfn,low,belong,stack:array[1..10000]of longint;
    dot:array[1..1000]of point;
    use:array[1..10000]of boolean;
    link:array[1..1000]of ar;
    num:array[1..1000]of longint;
    outs:array[1..1000]of integer;
    x,sum,total,top,step,belongx,a,b,i,j,n,m:longint;
    p:point;
procedure insert(a,b:longint);
var p:point;
begin
  new(p);
  p^.e:=b;
  p^.s:=dot[a];
  dot[a]:=p;
end;

procedure tarjan(i:longint);
var j:longint;
    p:point;
begin
  inc(step);
  low[i]:=step;
  dfn[i]:=step;
  inc(top);
  stack[top]:=i;
  use[i]:=true;
  p:=dot[i];
  while p<>nil do
    begin
      j:=p^.e;
      if dfn[j]=0
       then
        begin
          tarjan(j);
          if low[j]<low[i] then low[i]:=low[j];
        end
       else
        if (use[j])and(low[i]>low[j])
         then
          low[i]:=low[j];
     p:=p^.s;
    end;
  if dfn[i]=low[i]
   then
     begin
       inc(belongx);
       while (i<>j)do
         begin
          j:=stack[top];
          inc(num[belongx]);
          belong[j]:=belongx;
          link[belongx,num[belongx]]:=j;
          dec(top);
          use[j]:=false;
         end;
     end;
end;

procedure qsort(b,e:longint);
var t,l,r,m:longint;
begin
  l:=b;r:=e;m:=link[x,(l+r)>>1];
  while l<r do
    begin
      while link[x,l]<m do inc(l);
      while m<link[x,r] do dec(r);
      if l<=r then
        begin
          t:=link[x,l];
          link[x,l]:=link[x,r];
          link[x,r]:=t;
          inc(l);
          dec(r);
        end;
    end;
  if l<e then qsort(l,e);
  if b<r then qsort(b,r);
end;

begin

  readln(n,m);
  for i:=1 to m do
    begin
      readln(a,b);
      insert(a,b);
    end;
  for i:=1 to n do if dfn[i]=0 then tarjan(i);
  for i:=1 to n do
   begin
     p:=dot[i];
     while p<>nil do
       begin
         if belong[i]<>belong[p^.e]
           then
            begin
              inc(outs[belong[i]]);
            end;
         p:=p^.s;
       end;
   end;
  sum:=belongx;
  for i:=1 to belongx do
   if num[i]=1 then dec(sum);
  writeln(sum);
  for i:=1 to belongx do
    begin
      if (outs[i]=0)and(num[i]<>1) then
        begin
          inc(total);
          if total>1 then begin write(-1);halt;end;
          x:=i;
        end;
    end;
  if (total=0) then begin write(-1);halt;end;
  qsort(1,num[x]);
  for i:=1 to num[x] do write(link[x,i],' ');
  close(input);
end.


测试通过 Accepted

总耗时: 2 ms
0 / 0 数据通过测试.
运行结果
测试点#data0.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#data1.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#data2.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#data3.in  结果:AC    内存使用量:  256kB     时间使用量:  1ms     
测试点#data4.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#data5.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#data6.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#data7.in  结果:AC    内存使用量:  256kB     时间使用量:  0ms     
测试点#data8.in  结果:AC    内存使用量:  364kB     时间使用量:  1ms     
测试点#data9.in  结果:AC    内存使用量:  364kB     时间使用量:  0ms     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值