首页 > 代码库 > XJOI游戏

XJOI游戏

Description

暑假到了,次方又可以打网络游戏了。然而在一堆玩家中选择哪些人来刷副本可是一件伤脑筋的事。
现在有n个人,如果同时选择了i和j这两个人,则会产生Aij的战斗力加成。但是如果一共选择了k个人,那么会造成k*(200-k)的网络延迟。团队的总战斗力定义为所有人之间的战斗力加成的和/总的网络延迟。
次方想知道能得到的最大的战斗力是多少。

Input

第一行,一个整数n,表示总人数。
下面n行,每行n列,第i行第j列的元素Aij(0<=Aij<10)表示同时选择i和j带来的战力加成。(Aij=Aji,Aii=0)

Output

一行一个实数,表示战斗力值,保留五位小数。

Sample Input

3
0 7 1
7 0 2
1 2 0

Sample Output

0.01768

HINT

对于30%的数据,有N<=15 
对于100%的数据,有N<=50。

 

题解:

根据数据决定算法。

对于30%的较小数据,采用一定正确的暴力搜索,对于后70%——

模拟退火!

通过random来决定这一次操作是加入一个人还是去除一个人。

若执行这次操作后价值比原来优,则接受;若不如原来优,则以一定的几率t接受这个操作,随搜索的进行,几率t越来越小。

玄学搜索,大致原理是距离答案较远时盲目找,距离答案较近时尽量贪心的找。

 

代码:

技术分享
uses math;
var
  a:array[0..50,0..50]of longint;
  bo,q:array[0..50]of longint;
  i,j,k,l,n,m:longint;
  ans:extended;
procedure work;
var last,tmp,cnt,p,x,del,i:longint;
  t:extended;
begin
  last:=0; cnt:=0; t:=1;
  while t>0.00000001 do
  begin
    if random(2)=0 then
    begin
      if cnt=0 then continue;
      x:=random(n)+1;
      if bo[x]=1 then
      begin
        del:=0;
        for i:=1 to n do if bo[i]=1 then del:=del+a[i,x];
        tmp:=last-del;
        if((cnt-1>0)and(ans<tmp/((200-cnt+1)*(cnt-1))))or
        (random(10000)/10000<t)then
        begin
          last:=tmp; if cnt-1>0 then ans:=tmp/((200-cnt+1)*(cnt-1));
          dec(cnt); bo[x]:=0;
        end;
      end;
    end else
    begin
      if cnt=n then continue;
      x:=random(n)+1;
      if bo[x]=0 then
      begin
        del:=0;
        for i:=1 to n do if bo[i]=1 then del:=del+a[i,x];
        tmp:=last+del;
        if(ans<tmp/((200-cnt-1)*(cnt+1)))or(random(10000)/10000<t)then
        begin
          last:=tmp; ans:=tmp/((200-cnt-1)*(cnt+1));
          inc(cnt); bo[x]:=1;
        end;
      end;
    end;
    t:=t*0.99999;
  end;
end;
procedure ss(x,y,z:longint);
var i:longint;
begin
  if x>n then
  begin
    if y>0 then ans:=max(ans,z/(y*(200-y)));
    exit;
  end;
  ss(x+1,y,z);
  for i:=1 to x-1 do
  if bo[i]=1 then z:=z+a[x,i];
  bo[x]:=1; ss(x+1,y+1,z); bo[x]:=0;
end;
begin
  randomize;
  readln(n);
  for i:=1 to n do for j:=1 to n do read(a[i,j]);
  if n<=15 then ss(1,0,0)else work;
  writeln(ans:0:5);
end.
View Code

XJOI游戏