[Tyvj 2869]血缘关系

血缘关系

时间限制: 1 Sec 内存限制: 128 MB

题目描述

我们正在研究妖怪家族的血缘关系。每个妖怪都有相同数量的基因,但是不同的妖怪的基因可能是不同的。我们希望知道任意给定的两个妖怪之间究竟有多少相同的基因。由于基因数量相当庞大,直接检测是行不通的。但是,我们知道妖怪家族的家谱,所以我们可以根据家谱来估算两个妖怪之间相同基因的数量。
妖怪之间的基因继承关系相当简单:如果妖怪C是妖怪A和B的孩子,则C的任意一个基因只能是继承A或B的基因,继承A或B的概率各占50%。所有基因可认为是相互独立的,每个基因的继承关系不受别的基因影响。
现在,我们来定义两个妖怪X和Y的基因相似程度。例如,有一个家族,这个家族中有两个毫无关系(没有相同基因)的妖怪A和B,及它们的孩子C和D。那么C和D相似程度是多少呢?因为C和D的基因都来自A和B,从概率来说,各占50%。所以,依概率计算C和D平均有50%的相同基因,C和D的基因相似程度为50%。需要注意的是,如果A和B之间存在相同基因的话,C和D的基因相似程度就不再是50%了。
你的任务是写一个程序,对于给定的家谱以及成对出现的妖怪,计算它们之间的基因相似程度。

输入

第一行两个整数n和k。n(2≤n≤300)表示家族中成员数,它们分别用1,2,…,n来表示。k(0≤k≤n-2)表示这个家族中有父母的妖怪数量(其他的妖怪没有父母,它们之间可以认为毫无关系,即没有任何相同基因)。
接下来的k行,每行三个整数a,b,c,表示妖怪a是妖怪b和c的孩子。
然后是一行一个整数m(1≤m≤n2),表示需要计算基因相似程度的妖怪对数。
接下来的m行,每行两个整数,表示需要计算基因相似程度的两个妖怪。
你可以认为这里给出的家谱总是合法的。具体来说就是,没有任何的妖怪会成为自己的祖先,并且你也不必担心会存在性别错乱问题。

输出

共m行。第k行表示第k对妖怪之间的基因相似程度。你必须按百分比输出,有多少精度就输出多少,但不允许出现多余的0(注意,0.001的情况应输出0.1%,而不是.1%)。具体格式参见样例。

样例输入

7 4
4 1 2
5 2 3
6 4 5
7 5 6
4
1 2
2 6
7 5
3 3

样例输出

0%
50%
81.25%
100%

题解

  • 核心:dp[a,b]:=(f(x[a,1],b)+f(x[a,2],b))/2
  • 高精小数(这段代码有3个点有偏差,我估计只能是在高精小数上出了问题,如果有谁还看见我这段话,有兴趣看了我的代码一下,发现了问题,给我留言QAQAQAQAQ)
var
 dp:array[0..300,0..300]of longint;
 p:array[0..300,0..300]of longint;  //p[i,j]:点i的儿子有p[i,j]   p[i,0]:点i有p[i,0]个儿子
 w,x:array[0..300,1..2]of longint;  //x[i,1/2]:点i的父母     w[i,1]:拓扑点i的原数组点为w[i,1]     w[i,2]:原点i的拓扑点为w[i,2]
 rudu:array[0..300]of longint;   //点i的入度
 tt:array[0..90000,-1..300]of integer;
 z:array[0..300]of longint;
 t:ansistring;
 i,j,k,l,o:longint;
 n,m,ans:longint;
 a,b,c,v:longint;

procedure did(kk,a,b:longint);
var i,j,max,yu,ax,m,n,v:longint;
begin
 if tt[a,-1]>tt[b,-1]
 then max:=tt[a,-1]
 else max:=tt[b,-1];
 yu:=0;
 for i:=max downto 0 do
  begin
   tt[kk,i]:=(tt[a,i]+tt[b,i]+yu) mod 10;
   yu:=(tt[a,i]+tt[b,i]+yu) div 10;
  end;
 if (tt[kk,max]=0)and(max>=1)
 then dec(max);
 tt[kk,-1]:=max;
 yu:=0;
 for i:=0 to max do
  begin
   v:=tt[kk,i]+yu*10;
   tt[kk,i]:=v div 2;
   yu:=v mod 2;
  end;
 if yu<>0
 then begin tt[kk,-1]:=max+1; tt[kk,max+1]:=5; end;
end;

function f(a,b:longint):longint;
var c:longint;
begin
  if (w[a,2]<w[b,2])
  then begin c:=a; a:=b; b:=c; end;

  if tt[dp[a,b],0]<>-1
  then exit(dp[a,b])
  else
   begin
    did(dp[a,b],f(x[a,1],b),f(x[a,2],b));//dp[a,b]:=(f(x[a,1],b)+f(x[a,2],b))/2;
    exit(dp[a,b]);
   end;
end;

begin
 readln(n,m);
 for i:=1 to m do
  begin
   readln(a,b,c);
   x[a,1]:=b; x[a,2]:=c;
   inc(rudu[a],2);
   inc(p[b,0]); inc(p[c,0]);
   p[b,p[b,0]]:=a; p[c,p[c,0]]:=a;
  end;

 while w[0,1]<>n do
  begin
  z[0]:=0;
  for i:=1 to n do
   if rudu[i]=0
   then
    begin
     inc(w[0,1]); w[i,2]:=w[0,1]; w[w[0,1],1]:=i;
     for j:=1 to p[i,0] do
      begin
       inc(z[0]);
       z[z[0]]:=p[i,j];
      end;
     rudu[i]:=-1;
    end;
  for i:=1 to z[0] do
   dec(rudu[z[i]]);
  end;

 o:=0;
 for i:=1 to n do
  for j:=1 to n do
   if i=j
   then begin inc(o); dp[i,j]:=o; tt[o,0]:=1; end
   else
    if (x[i,1]=0)and(x[j,1]=0)
    then begin  inc(o); dp[i,j]:=o; tt[o,0]:=0; end
    else begin  inc(o); dp[i,j]:=o; tt[o,0]:=-1; end;

 readln(m);
 for i:=1 to m do
  begin
   readln(a,b);
   ans:=f(a,b);
   for j:=tt[ans,-1] downto 1 do
    if tt[ans,j]=0
    then dec(tt[ans,j])
    else break;
   if tt[ans,0]=1
   then writeln('100%')
   else
    if (tt[ans,0]=0)and(tt[ans,-1]=0)
    then writeln('0%')
    else
     begin
      for j:=1 to 2 do
       if tt[ans,j]<>0
       then begin v:=j; break; end;
      if v=0
      then write('0')
      else
       for j:=v to 2 do
        write(tt[ans,j]);
      if tt[ans,-1]>2
      then write('.');
      for j:=3 to tt[ans,-1] do
       write(tt[ans,j]);
      writeln('%');
     end;
  end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值