关押罪犯(noip2010)

  解法:

         (1)搜索(30分)

        (2)二分(此题属于最大值最小问题)

        (3)贪心+并查集

 下面着重说一下“贪心+并查集”

  因为有A、B两座监狱,每个犯人不是在A,就是在B监狱。

   至于每个犯人在那个监狱,我们可以人为的指定,但在指定时要考虑和他有怨气的所有人,太复杂了!

  反过来,我们可以从全局考虑:用x0表示x的反集合,y0表示y的反集合,也就是说如果不跟x同集合那就一定跟x0同集合,同理,如果不跟y同集合就一定跟y0同集合...

   这样先排序,从大到小往不同的集合中添加边的两个端点,每次判断是否有冲突,若有冲突(说明该边的两个端点在前面比他大的边的分配中已经分配到同一个集合,那么该边就是符合要求的最大边),那么就输出,否则合并..

type

  node=record

       x,y,data:longint;

       end;



var

  n,m:longint;

  bo:boolean;

  a:array[0..100100]of node;

  f:array[0..40100] of longint;

  procedure init;

  var i:longint;

  begin

    bo:=false;

    readln(n,m);

    for i:=1 to m do readln(a[i].x,a[i].y,a[i].data);

  end;

  procedure qsort(l,r:longint);

  var mid,i,j:longint;t:node;

  begin

    mid:=a[(L+R)div 2].data;

    i:=l;j:=r;

    while i<j do

      begin

        while a[i].data<mid do inc(i);

        while a[j].data>mid do dec(j);

        if i<=j then begin  t:=a[i];a[i]:=a[j];a[j]:=t; inc(i);dec(j); end;

      end;

      if i<r then qsort(i,r);

      if j>l then qsort(l,j);

  end;

  function find(x:longint):longint;

  begin

    if f[x]=x then exit(x);

    if f[f[x]]=f[x] then exit(f[x]);

    find:=find(f[x]); f[x]:=find;

  end;

  procedure main;

  var i,x,y,x0,y0,nn:longint;

  begin

    nn:=n+n;

    for i:=1 to nn do f[i]:=i;

    qsort(1,m);

    for i:=m downto 1 do

      begin

        x:=a[i].x;y:=a[i].y;x0:=n+x;y0:=n+y;

        x:=find(x);y:=find(y);x0:=find(x0);y0:=find(y0);

        if (x=y){or(x0=y0)} then begin writeln(a[i].data);bo:=true;break;end;

        if x<>y0 then f[x]:=y0;

        if y<>x0 then f[y]:=x0;

      end;

  end;

begin

  assign(input,'prison.in');reset(input);

  assign(output,'prison.out');rewrite(output);

  init;

  main;

  if not bo then write(0);

  close(input);close(output);

end.
View Code

 

你可能感兴趣的:(IP)