PAS蜜汁WA

P1285 队员分组

我很辣ji看签名 @ 2017-10-31 13:52:54

program teams2;
type
  ty=record
    a,b:set of 1..100;
  end;
var
  ren:array[1..100,1..100] of boolean;
  get:array[1..100] of boolean;
  zu1,zu2,a:array[1..100] of longint;
  f,g:array[1..100,-200..200] of boolean;
  n,i,j,x,total,r,l:longint;
  dom:array[1..100] of ty;
procedure sou(x,y:longint);{构建骨牌}
var
  i,j,k:longint;
begin
  get[x]:=true;
  for i:=1 to n do
  begin
    if ((not ren[x,i])or(not ren[i,x])) then  {互不认识放入相反组}
    begin
      if y=1 then
      begin
        if (get[i])and(i in dom[total].a) then  {是否矛盾}
        begin
          writeln('No solution');
          close(output);
          halt;
        end;
        if get[i] then continue;  {不矛盾直接跳过,避免死循环}
        dom[total].b:=dom[total].b+[i];
        sou(i,2);
      end;
      if y=2 then
      begin
        if (get[i])and(i in dom[total].b) then
        begin
          writeln('No solution');
          halt;
        end;
        if get[i] then continue;
        dom[total].a:=dom[total].a+[i];
        sou(i,1);
      end;
    end;
  end;
end;
procedure huisu(x,y:longint); {回溯输出方案}
var
  i:longint;
begin
  if x=0 then exit;
  if g[x,y] then    {g[x,y]=true:当前x骨牌翻了}
  begin            
    for i:=1 to n do
    if i in dom[x].a then begin inc(l); zu2[l]:=i; end;
    for i:=1 to n do
    if i in dom[x].b then begin inc(r); zu1[r]:=i; end;
    huisu(x-1,y+a[x]);
  end
  else
  begin            {g[x,y]=false:当前骨牌没翻}  
    for i:=1 to n do
    if i in dom[x].a then begin inc(r); zu1[r]:=i; end;
    for i:=1 to n do
    if i in dom[x].b then begin inc(l); zu2[l]:=i; end;
    huisu(x-1,y-a[x]);
  end;
end;
begin
  read(n);
  for i:=1 to n do
  begin
    for j:=1 to n do
    begin
      read(x);
      if x<>0 then
      ren[i,x]:=true
      else break;
    end;
    ren[i,i]:=true;           {认识自己....}
  end;
  total:=0;
  for i:=1 to n do
  if not get[i] then
  begin
  inc(total);
  dom[total].a:=dom[total].a+[i];
  sou(i,1);
  end;
  for i:=1 to total do{保存骨牌上下差,要用动归使所有骨牌上下差之和最小;上代表组1,下代表组2,差代表组1、组2人数差}
  begin
  for j:=1 to n do
  if j in dom[i].a then
  begin
   inc(a[i]);
  end;
  for j:=1 to n do
  if j in dom[i].b then
  begin
   dec(a[i]);
  end;  
  end;
   f[1,a[1]]:=true;
  g[1,a[1]]:=false;
   f[1,-a[1]]:=true;
   g[1,-a[1]]:=true;
   for i:=2 to total do
    for j:=-n to n do
    begin
      if (j-a[i]>=-n)and(j-a[i]<=n)
      and(f[i-1,j-a[i]])               {f[x,y]:到第x个骨牌,组1组2人数差能否达到y}
      then                             {g[x,y]:记录当前骨牌是否翻转}
      begin
      f[i,j]:=true;
      g[i,j]:=false;
      end;
      if (j+a[i]>=-n)and(j+a[i]<=n)
      and(f[i-1,j+a[i]])
      then
      begin
      f[i,j]:=true;
      g[i,j]:=true;
      end;
    end;
  r:=0; l:=0;
  for i:=0 to n do                         {回溯输方案}
  begin
  if f[total,i] then
  begin
   huisu(total,i);
   write((i+n) div 2,' ');
   for j:=1 to r do write(zu1[j],' ');
   writeln;
   write(n-(i+n) div 2,' ');
   for j:=1 to l do write(zu2[j],' ');
   halt;
  end;
  if f[total,-i] then
  begin
   huisu(total,-i);
   write((n-i) div 2,' ');
   for j:=1 to r do write(zu1[j],' ');
   writeln;
   write(n-(n-i) div 2,' ');
   for j:=1 to l do write(zu2[j],' ');
   halt;
  end;
  end;
end.

|