每读入一个数集,就要把集合中重复的数字去掉,保证单个集合中每个元素都是distinct的。
这样,计算两个数集的similarity值的时候,只需要计算两个集合的交集,也就是它们之间的公共的元素个数c,而答案就等于c/(集合1的成员数+集合2的成员数-c)。
为了加快计算公共元素的速度,我把每个集合都排序过,每个集合中的元素都是升序排列的,所以检验一个元素是否为某个集合的成员时,可以用二分查找。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=10005;
typedef struct sett{
int shu[N];
int num;
sett(){num=0;}
void inpu(){
int i,t[N],n;
scanf("%d",&n);
if(n<=0)return;
for(i=0;i<n;i++)
scanf("%d",&t[i]);
sort(t,t+n);
shu[0]=t[0];
num=1;
for(i=1;i<n;i++)
if(t[i]>t[i-1])
shu[num++]=t[i];
}
int find(int x){
if(num<=0)return -1;
int lf=0,rt=num-1,mid=(lf+rt)/2;
if(x<shu[lf]||x>shu[rt])return -1;
while(1){
if(shu[mid]==x)return mid;
if(lf==rt)return -1;
if(shu[mid]<x)
lf=mid+1;
else if(shu[mid]>x)
rt=mid;
mid=(lf+rt)/2;
}
}
}sett;
sett se[55];
int n;
double ans[55][55];
void func(int a,int b){
if(ans[a][b]!=-1){
printf("%.1lf%%\n",ans[a][b]);
return;
}
double com=0,dis=se[a].num+se[b].num;
int i;
for(i=0;i<se[b].num;i++){
if(se[a].find(se[b].shu[i])>=0){
com+=1;
dis-=1;
}
}
ans[a][b]=(com/dis)*100.0;
printf("%.1lf%%\n",ans[a][b]);
}
int main(){
int i,j;
scanf("%d",&n);
for(i=0;i<n;i++)
se[i].inpu();
for(i=0;i<55;i++)
for(j=0;j<55;j++)
ans[i][j]=-1;
int m,a,b;
scanf("%d",&m);
while(m--){
scanf("%d%d",&a,&b);
func(a-1,b-1);
}
return 0;
}