目录见右上
站内文章欢迎各位转载,但是请注明出处(毕竟码字很辛苦哈)。

主题

1019 集合论与图论

题目描述 Description

       集合论与图论对于小松来说是比数字逻辑轻松,比数据结构难的一门专业必修课。虽然小松在高中的时候已经自学过了离散数学中的图论,组合,群论等知识。但对于集合论,小松还是比较陌生的。集合论的好多东西也涉及到了图论的知识。

 

       在第四讲的学习中,小松学到了“有序对”这么一个概念,即用<x, y>表示有序对x和y。要注意的是有序对<x, y>不等于有序对<y, x>。对于一个有序对集合R={<x,y>, <y, z>, <x,  z>,……},我们说R是传递的,当且仅当他满足下面的性质:

 

红色字体用直观的语言描述是:如果存在<x, y>∈R,<y, z>∈R,那么一定存在<x, z>∈R

 

       这里集合R可以对应到一个有向图G,有序对<x ,y>对应到了G中的一条有向边。 你现在的任务是,对于任意给定的一个简单有向图G(同一有向边不出现两次),判断G是否具有传递性。

 

输入描述 Input Description

       输入文件set.in第一行包含测试数据的个数T(1<=T<=10)。接下来T组测试数据,每组测试数据第一行包含两个个整数n和m(1<=n<=1000, n<=m<=100000),表示G中元素个数和有向边的个数,接下来的m行每行2个整数x, y(1<=x,y<=n)表示x与y之间有一条有向边连接。

输出描述 Output Description

       对于每组数据,如果G是传递的,你需要向输出文件set.out输出一行”Yes”, 否则输出一行”No”。

样例输入 Sample Input

2

3 3

1 2

1 3

2 3

4 5

1 2

1 3

1 4

2 3

3 4

样例输出 Sample Output

Yes

No

数据范围及提示 Data Size & Hint

有30%满足1<=n<=100, 1<=m<=10000;

有100%的数据满足1<=n<=1000, 1<=m<=100000;


个人解法:

我真的好想想一个O(n)的算法,然后发现完全不必要。

于是就按照题目给的范围来做了。

首先如果<a,b>,且<b,c>,那么a是可以到c的,这个时候如果没有<a,c>那么R就不是传递的。

所以我们的任务就是对于某一个点x,判断是否存在一个点y,使得x到y没有边,但是x可以到达y。

如果存在,那么R就是不传递的。如果对于所有的点都判断完了,仍然符合要求,那么R就是传递的。

更有趣的是不用写hash——只有1000*1000的表。

正如楼下所说,开一个邻接链表,再开一个邻接矩阵。

至于判断,我们可以用BFS跑完一张图。

对于一组数据,总的复杂度是O(n^2)。


代码如下:

type

inf=record

      x,next:longint;//邻接链表的边

     end;


var

Arr,Arrmap:array[1..1000] of longint;//Arr是BFS的队列,Arrmap是邻接链表存图的数组

map:array[1..1000,1..1000] of boolean;//邻接矩阵

Arre:array[1..100000] of inf;//邻接链表的边

Vis:array[1..1000] of boolean;//BFS是判断是否遍历过

T,vt,vp,i,n,m,top:longint;

flag:boolean;//判断R是否传递


procedure ins(f,s:longint);//插入一条边

begin

  inc(top);

  Arre[top].x:=s;

  Arre[top].next:=Arrmap[f];

  Arrmap[f]:=top;

end;


procedure Linit;//初始化

var

  vi,u,v:longint;

begin

  fillchar(map,sizeof(map),false);

  fillchar(Arrmap,sizeof(Arrmap),0);//常数写这么大都还过了——唉看来是我想多了

  fillchar(Arre,sizeof(Arre),0);

  v:=0; i:=0; n:=0; m:=0; top:=0;

  flag:=true;

  read(n,m);

  for vi:=1 to m do

  begin

   read(u,v);

   map[u,v]:=true;//更新邻接链表与邻接矩阵

   ins(u,v);

  end;

end;


function BFS(x:longint):boolean;//跑BFS

var

  h,t,v:longint;

begin

  fillchar(Arr,sizeof(Arr),0);

  fillchar(Vis,sizeof(Vis),false);

  h:=0;

  t:=1;

  Arr[1]:=x;

  vis[x]:=true;

  while h<t do

  begin

   inc(h);

   v:=Arrmap[Arr[h]];

   while v<>0 do

   begin

    if not vis[Arre[v].x] then

    begin

     inc(t);

     Arr[t]:=Arre[v].x;

     Vis[Arr[t]]:=true;

     if not map[x,Arre[v].x] then exit(false);//如果x可以到达e[v],x,然而邻接矩阵中没有这条边,说明R不具有传递性,弹出false

    end;

    v:=Arre[v].next;

   end;

  end;

  exit(true);//如果遍历完了没有发现不合法的点,那么弹出true

end;


begin

read(T);//读入多组数据

randomize;

for vt:=1 to T do

begin

  Linit;//初始化

  vp:=1+random(n);//我以为从1开始枚举会卡数据(也就是最后一个点才出现不合法的状态),所以随机了一下


  for i:=vp to n do

  begin

   if not flag then break;

   flag:=BFS(i);

  end;

  for i:=vp-1 downto 1 do

  begin

   if not flag then break;//跑BFS判断R是否传递

   flag:=BFS(i);

  end;


  if not flag then writeln('No')

   else writeln('Yes');//输出

end;

end.


评论
©主题 —— Powered by LOFTER