Problem:2118
Time Limit:3000ms
Memory Limit:665535K
Description
給出兩個數集,它們的相似程度定義爲Nc/Nt*100%。其中,Nc表示兩個數集中相等的、兩兩互不相同的元素個數,而Nt表示兩個數集中總共的互不相同的元素個數。請計算任意兩個給出數集的相似程度。
Input
輸入第一行給出一個正整數N(N<=50),是集合的個數。隨後N行,每行對應一個集合。每個集合首先給出一個正整數M(M<=10^4),是集合中元素的個數;然後跟M個[0, 10^9]區間內的整數。
之後一行給出一個正整數K(K<=2000),隨後K行,每行對應一對需要計算相似度的集合的編號(集合從1到N編號)。數字間以空格分隔。
Output
輸出共K行,每行一個保留2位小數的實數,表示給定兩個集合的相似度值。
Sample Input
3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3
Sample Output
50.00%
33.33%
Source
信息學奧賽課課通
Tips
很容易超時,在瘋狂的優化下終於 AC 了。
最開始編譯器卡了一下,我以爲 set 數組很慢,不能用 set 數組,然後就改成數組排序去重了,結果差不多,正常應該是怎麼解都行。
蒟蒻的一些思路:
首先,把所有集合讀入數組,讀完立刻去重,採用 sort+unique 方式。
然後依次讀取要比較的兩個集合,由於之前已經排好序了,所以只需要按順序比較找出兩數組中相同元素個數即可。
注:使用 unique 前需要先進行排序。
Code
#include <bits/stdc++.h>
using namespace std;
int main()
{
int arr[50][10001]; //存儲集合中各個元素,多的最後一位存集合中元素個數
double ans[50][50]={0},r; //ans記錄之前的查詢
int n,num,s1,s2,same,tmp,sp1,sp2;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&arr[i][10000]);
for(int j=0;j<arr[i][10000];j++)
{
scanf("%d",&arr[i][j]);
}
sort(arr[i],arr[i]+arr[i][10000]); //排序
arr[i][10000]=unique(arr[i],arr[i]+arr[i][10000])-arr[i]; //去重
}
scanf("%d",&n);
while(n--)
{
scanf("%d %d",&s1,&s2);
if(ans[s1-1][s2-1]!=0) //已經計算過直接輸出
{
printf("%.2f%\n",ans[s1-1][s2-1]);
continue;
}
same=0;
sp1=sp2=0;
while(sp1<arr[s1-1][10000]&&sp2<arr[s2-1][10000]) //比較獲取相同元素個數
{
//小的元素指針+1,元素相等same+1
if(arr[s1-1][sp1]<arr[s2-1][sp2])sp1++;
else if(arr[s1-1][sp1]>arr[s2-1][sp2])sp2++;
else
{
same++;
sp1++;
sp2++;
}
}
r=same*100.0/(arr[s1-1][10000]+arr[s2-1][10000]-same); //計算答案
ans[s1-1][s2-1]=ans[s2-1][s1-1]=r; //存儲答案
printf("%.2f%\n",r);
}
return 0;
}