https://www.luogu.com.cn/problem/P1235
题目描述
我们正在研究妖怪家族的血缘关系。每个妖怪都有相同数量的基因,但是不同的妖怪的基因可能是不同的。我们希望知道任意给定的两个妖怪之间究竟有多少相同的基因。由于基因数量相当庞大,直接检测是行不通的。但是,我们知道妖怪家族的家谱,所以我们可以根据家谱来估算两个妖怪之间相同基因的数量。
妖怪之间的基因继承关系相当简单:如果妖怪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的孩子。
然后是一行一个整数m(1≤m≤n2),表示需要计算基因相似程度的妖怪对数。
接下来的m行,每行两个整数,表示需要计算基因相似程度的两个妖怪。
你可以认为这里给出的家谱总是合法的。具体来说就是,没有任何的妖怪会成为自己的祖先,并且你也不必担心会存在性别错乱问题。
输出格式
共m行。可k行表示第k对妖怪之间的基因相似程度。你必须按百分比输出,有多少精度就输出多少,而且必须准确,但不允许出现多余的0(注意,0.001的情况应输出0.1%,而不是.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
输出 #1复制
0%
50%
81.25%
100%
上代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pll pair<LL,LL>
#define mkp make_pair
#define X first
#define Y second
#define N 305
int n,m,fa[N],mo[N];
int he[N],ne[N<<1],to[N<<1],tot;
int q[N],in[N];
struct DATA{short dat[N];int ln;}f[N][N];
DATA operator +(DATA x,DATA y){
x.ln=max(x.ln,y.ln);
int i;per(i,x.ln,1)
if((x.dat[i]+=y.dat[i])>9)++x.dat[i-1],x.dat[i]-=10;
x.dat[0]+=y.dat[0];
while(x.ln&&!x.dat[x.ln])--x.ln;
return x;
}
DATA div2(DATA x){
int i;
rep(i,0,x.ln){
if(x.dat[i]&1)x.dat[i+1]+=10;
x.dat[i]>>=1;
}
if(x.dat[x.ln+1])x.dat[++x.ln]=5;
return x;
}
void add(int x,int y){
to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
int read(){
int x=0;char ch=G;
while(ch<48||ch>57)ch=G;
for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
return x;
}
void BFS(){
int Ft=1,Rr=1,u,v,i;
rep(i,1,n){
if(!in[i])q[Rr++]=i;f[i][i].dat[0]=1;
}
while(Ft<Rr){
u=q[Ft++];
per(i,Ft-2,1){
v=q[i];f[u][v]=f[v][u]=div2(f[v][fa[u]]+f[v][mo[u]]);
}
for(i=he[u];i;i=ne[i])if(--in[v=to[i]]==0)q[Rr++]=v;
}
}
void write(DATA x){
printf("%d",x.dat[0]*100+x.dat[1]*10+x.dat[2]);int i;
if(x.ln>2){
putchar('.');
rep(i,3,x.ln)printf("%d",x.dat[i]);
}
puts("%");
}
int main(){
int i,x,Q,y;
n=read();m=read();
while(m--){
in[x=read()]=2;fa[x]=read();mo[x]=read();
add(fa[x],x);add(mo[x],x);
}
BFS();
for(Q=read();Q--;){
x=read();y=read();write(f[x][y]);
}
return 0;
}