组队

题目大意:给你n个人以及他们之间的关系,求最多能有多少个互相认识的人以及最多人数的方案数。

其实差不多是裸搜,用一个二进制数储存关系,加入的时候and一下就行。

但是直接搜的话会有很多重复状态,考虑一种搜索方式绝对不会出现重复状态。

于是我们规定外层用一种搜索顺序,内层的搜索顺序与外层相反,这样就保证内层搜的时候可以利用原来的结果。并且新加入一个节点的时候它只能去找那些以前已经搜索过的建环,这样可以保证没有重复的环。

这里有个很重要的剪枝,当搜到一个节点的时候,如果当前已经在环里的人数加上这个节点之后能加入的最大人数还小于当前的max,那么就可以直接退出这一层搜索。

这个剪枝对于这道题真的非常强……

program Neayo;
const
        inf='input.txt';
        ouf='output.txt';
var
        i,n,m,max,maxi,j:longint;
        a,s:array[0..51]of int64;
        g:array[0..51]of longint;
procedure init;
var x,y:longint;

begin
     assign(input,inf);assign(output,ouf);
     reset(input);rewrite(output);
     readln(n,m);
     s[1]:=1;
     for i:=2 to n do s[i]:=s[i-1]<<1;
     a:=s;
      for i:=1 to m do
     begin
          readln(x,y);
          a[x]:=a[x] or s[y];
          a[y]:=a[y] or s[x];
     end;
     close(input);
end;
procedure dfs(pre,num:longint;now:int64);
var i:longint;
begin
     if num=max then inc(maxi);
     if num>max then
     begin
          maxi:=1;
          max:=num;
     end;
     for i:=pre to n do
     begin
          if g[i]+num<max then exit;
          if now shr (i-1) and 1<>0 then
          begin
               dfs(i+1,num+1,now and a[i]);
          end;
     end;
end;
procedure go;
begin
      for j:=n downto 1 do
     begin
          dfs(j+1,1,a[j]);
          g[j]:=max;
     end;
     writeln(max,' ',maxi)
end;
begin
     init;
     go;
     close(output);
end.                                    

 

 

posted @ 2012-10-14 20:28  neayo  阅读(152)  评论(0编辑  收藏  举报