NEFU OJ 2118 相似的數集高級版-set

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章