zoukankan      html  css  js  c++  java
  • 并查集基础练习

    1.团伙(group.pas/c/cpp)

    AYYZOJ p1948

    题目分析:

    题目大意是有n个人求最多可能有几个团伙,由题意很容易想到用并查集解决。我们可以先假设每个人都不认识,在这一前提下可以保证团伙最多。在处理朋友的时候,把所有是朋友的人加入同一团伙;处理两人是敌人的时候,需要事先记录下每个人的敌人,然后依次把敌人的敌人加入同一团伙。最后统计有多少个团伙即可。

     1 var d:array[0..1000,0..1000] of longint;  //d[i][j]存储第i个人的第j个敌人
     2     f:array[0..1000] of longint;
     3     i,j,m,n,x,y,k,fx,fy,ans:longint;
     4 function get_father(x:longint):longint;
     5 begin
     6  if f[x]=0 then
     7   begin
     8    get_father:=x;
     9   end      else
    10   begin
    11    get_father:=get_father(f[x]);
    12    f[x]:=get_father;
    13   end;
    14 end;
    15 
    16 begin
    17 fillchar(f,sizeof(f),0);
    18   fillchar(d,sizeof(d),0);
    19  readln(n,m);
    20  for i:=1 to m do
    21   begin
    22    readln(k,x,y);
    23    fx:=get_father(x); fy:=get_father(y);
    24    if k=0 then                            //如果x,y是朋友则合并。
    25     begin
    26      if fx<>fy then f[y]:=fx;
    27     end;
    28    if k=1 then
    29     begin
    30      inc(d[x,0]); d[x,d[x,0]]:=y;            //d[x,0]记录x的敌人数
    31      inc(d[y,0]); d[y,d[y,0]]:=x;            //d[y,0]记录y的敌人数
    32 //如果x,y是敌人,则把x并入y的所有敌人中,y并入x的敌人中
    33      for j:=1 to d[y,0] do
    34       if fx<>get_father(d[y,j]) then f[d[y,j]]:=fx;        
    35      for j:=1 to d[x,0] do
    36       if fy<>get_father(d[x,j]) then f[d[x,j]]:=fy;
    37     end;
    38   end;
    39 ans:=0;
    40  for i:=1 to n do
    41   if f[i]=0 then inc(ans);            //如果自己就是树的根表明是一个集合
    42 writeln(ans);
    43 end.
    参考程序1
     1 var
     2  a:array[1..1000,0..1000]of longint;
     3  i,j,k,n,m,t,s:longint;
     4  fa:array[1..1000]of longint;
     5 function getfa(x:longint):longint;
     6 begin
     7  if fa[x]=0 then getfa:=x
     8             else
     9              begin
    10               fa[x]:=getfa(fa[x]);
    11               getfa:=fa[x];
    12              end;
    13 end;
    14 procedure union(x,y:longint);
    15 var i,j:longint;
    16 begin
    17  i:=getfa(x);
    18  j:=getfa(y);
    19  if i<>j then fa[i]:=j;
    20 end;
    21 begin
    22  readln(n,m);
    23  for i:=1 to m do
    24  begin
    25   readln(j,k,t);
    26   if j=0 then union(k,t)
    27           else begin
    28                 inc(a[k,0]);
    29                 a[k,a[k,0]]:=t;
    30                 inc(a[t,0]);
    31                 a[t,a[t,0]]:=k;
    32                end;
    33  end;
    34  for i:=1 to n do
    35   for j:=1 to a[i,0] do
    36    union(a[i,1],a[i,j]);
    37  for i:=1 to n do
    38   if getfa(i)=i then inc(s);
    39   writeln(s);
    40 end.
    参考程序2

    我比较倾向于参考程序2,程序1有点不理解。

    2.打击犯罪(black.pas/c/cpp)

    AYYZOJ p1949

    分析:

    因为打击犯罪的顺序为由前到后依次打击,很容易想到可以倒序合并(为什么我想不到,太弱了。。),一旦某一团伙的危险程度>n/2,停止输出即可。

    至于团伙的危险等级的确认,可以新建一个count数组,在合并时累加即可。

    下面分析为转载:来源

    此题首先要理解题意,题意意思是按顺序删点,如果删掉k点后,1~k-1的点也被删掉这样就好解决了,那怎么和并查集联系起来呢?我们可以这样理解,我从1开始删点如当前删了点k这对大于k的点进行并查集,并得时候更新根节点的节点数,如果最大的节点数大于(n+1)/2则继续删点,直到最大集合节点数小于等于(n+1)/2为止,但这样做每删一个点,并查集就得重新计算一次,那我们换一个思路,我们倒过来,我们不删点,我们求删点完后剩下的图组成的集合,我假设删点删到了k那剩下的图就是由k~n之间的的点组成如果他们组成的结合最大子图节点数不大(n+1)/2则说明k不该删,则继续往前推。

     1 var
     2   i,j,k,l,m,n:longint;
     3   f,c:array[1..1000] of longint;      //count数组
     4   g:array[1..1000] of boolean;
     5   a:array[0..1000,0..1000] of longint;
     6 function getfa(x:longint):longint;
     7 begin
     8   if f[x]=0 then exit(x);
     9   f[x]:=getfa(f[x]);
    10   getfa:=f[x];
    11 end;
    12 procedure together(x,y:longint);
    13 var i,j:longint;
    14 begin
    15   i:=getfa(x);
    16   j:=getfa(y);
    17   if i<>j then
    18   begin
    19     f[i]:=j;
    20     c[j]:=c[i]+c[j];
    21     c[i]:=0;
    22   end;
    23 end;
    24 begin
    25   readln(n);
    26   for i:=1 to n do c[i]:=1;
    27   for i:=1 to n do
    28    begin
    29      read(a[i,0]);
    30      for j:=1 to a[i,0] do read(a[i,j]);
    31    end;
    32   for i:=n downto 1 do
    33    begin
    34      for j:=1 to a[i,0] do
    35       if a[i,j]>i then
    36        together(i,a[i,j]);
    37      l:=0;
    38      for j:=1 to n do if c[j]>n div 2 then l:=1;
    39      if l=1 then
    40       begin
    41         writeln(i);
    42         break;
    43       end;
    44    end;
    45 end.
    参考程序
  • 相关阅读:
    mysql BETWEEN操作符 语法
    mysql IN操作符 语法
    mysql LIKE通配符 语法
    mysql TOP语句 语法
    mysql DELETE语句 语法
    mysql Update语句 语法
    mysql INSERT语句 语法
    mysql ORDER BY语句 语法
    mysql OR运算符 语法
    mysql AND运算符 语法
  • 原文地址:https://www.cnblogs.com/vacation/p/5418551.html
Copyright © 2011-2022 走看看