題目鏈接:https://www.patest.cn/contests/gplt/L2-005
L2-005. 集合相似度
給定兩個整數集合,它們的相似度定義為:Nc/Nt*100%。其中Nc是兩個集合都有的不相等整數的個數,Nt是兩個集合一共有的不相等整數的個數。你的任務就是計算任意一對給定集合的相似度。
輸入格式:
輸入第一行給出一個正整數N(<=50),是集合的個數。隨后N行,每行對應一個集合。每個集合首先給出一個正整數M(<=104),是集合中元素的個數;然后跟M個[0, 109]區間內的整數。
之后一行給出一個正整數K(<=2000),隨后K行,每行對應一對需要計算相似度的集合的編號(集合從1到N編號)。數字間以空格分隔。
輸出格式:
對每一對需要計算的集合,在一行中輸出它們的相似度,為保留小數點后2位的百分比數字。
輸入樣例:3 3 99 87 101 4 87 101 5 87 7 99 101 18 5 135 18 99 2 1 2 1 3輸出樣例:
50.00% 33.33%
感謝:
分析:
其實這道題只要把題意理解了就ok了,無論如何先將兩個集合去重得到新集合,“兩個集合都有的不相等整數的個數”意思是兩個集合的
交集個數,“兩個集合一共有的不相等整數的個數”意思是先將兩個集合並起來再去重得到的集合元素個數,理解題意后發現用c++中的set可以
很好的解決這一問題。通過這一題我也對set用法有了更深的體會。(不相等整數的個數 去重)
1.求兩集合交集
2.求兩集合合並去重后 集合內 元素個數(並集)
集合的交並操作,直接利用set
進行處理,因為set
有去重的功能,而且set
是利用紅黑樹實現的,查找速度快O(logN)
C++ STL SET容器學習
http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/13/2636375.html
http://www.cplusplus.com/reference/set/set/
#include "cstdio" #include "set" #include "map" using namespace std; int Set[500020];///存儲所有集合 struct locate{ int start;///集合開始下標 int len;///集合長度 }locate_set;///每個集合定位 int main() { int n; set<int> s1,s2; map<int,locate> SetFlag;///集合定位 while(~scanf("%d",&n)&&n){ int flag=1,p=0,m=0; for(int i=0;i<n;i++){ scanf("%d",&m); locate_set.len=m; locate_set.start=p; SetFlag[flag++]=locate_set; for(int j=0;j<m;j++){ scanf("%d",&Set[p++]); } } ///測試 int k=0,test1=0,test2=0; scanf("%d",&k); for(int i=0;i<k;i++){ s1.clear();s2.clear(); scanf("%d%d",&test1,&test2); s1.insert(Set+SetFlag[test1].start,Set+SetFlag[test1].start+SetFlag[test1].len); s2.insert(Set+SetFlag[test2].start,Set+SetFlag[test2].start+SetFlag[test2].len); int Count1=0,Count2=0;///交集並集 元素個數 set<int>::iterator iter; for(iter = s1.begin() ; iter != s1.end() ; ++iter) { if(s2.find(*iter)!=s2.end()){ Count1++; } } //printf("%d\n",Count1); s1.insert(s2.begin(),s2.end()); Count2=s1.size(); printf("%.2lf%%\n",(double)Count1/Count2*100); } } }
悲哀的,最后一個,運行超時。。可能最后一個測試數據太多,而我的算法效率有問題!
學習學長學姐版本:
學長:http://www.cnblogs.com/yinzm/p/5498633.html
#include<cstdio> #include<set> #include<cstdlib> using namespace std; const int maxn = 55; set<int> s[maxn]; int n; int main() { while(~scanf("%d", &n)) { int cnt; for(int i = 0; i < n; i++) { if(!s[i].empty())s[i].clear(); scanf("%d", &cnt); int x; for(int j = 0; j < cnt; j++) { scanf("%d", &x); s[i].insert(x); } } scanf("%d", &cnt); int u,v; for(int i = 0; i < cnt; i++) { scanf("%d%d", &u, &v); u--,v--; int same = 0; int size_s1 = s[u].size(); int size_s2 = s[v].size(); set<int>::iterator it; for(it = s[u].begin(); it != s[u].end(); it++) { if(s[v].find(*it) != s[v].end()) { same++; } } int nc = same; int nt = size_s1+size_s2-same; double ans = (nc*1.0)/(nt*1.0)*100; printf("%.2lf%%\n", ans); } } return 0; }
可已看出,我的代碼明顯復雜,我繞了一大圈,而人家直接定義一個set數組。也不知道當時腦子抽的什么風。
但是沒關系,我很弱,但在提升。
學姐:http://www.liuchuo.net/archives/2079
#include <set> #include <vector> #include <cstdio> using namespace std; int main() { int n, m, k, temp, a, b; scanf("%d", &n); vector<set<int>> v(n); for(int i = 0; i < n; i++) { scanf("%d", &m); set<int> s; for(int j = 0; j < m; j++) { scanf("%d", &temp); s.insert(temp); } v[i] = s; } scanf("%d", &k); for(int i = 0; i < k; i++) { scanf("%d %d", &a, &b); int nc = 0, nt = v[b-1].size(); for(auto it = v[a-1].begin(); it != v[a-1].end(); it++) { if(v[b-1].find(*it) == v[b-1].end()) {//同時計算並交集 nt++; } else { nc++; } } double ans = (double)nc / nt * 100; printf("%.2f%%\n", ans); } return 0; }
揭穿事實,不要逃避。

#include "cstdio" #include "set" using namespace std; int main() { set<int> Set[55]; int n,m,temp,k; while(~scanf("%d",&n)&&n){ for(int i=0;i<n;i++){ scanf("%d",&m); for(int j=0;j<m;j++){ scanf("%d",&temp); Set[i].insert(temp); } } scanf("%d",&k); int n=0,u=0,test01,test02; for(int i=0;i<k;i++){ scanf("%d%d",&test01,&test02); test01--; test02--; n=0;u=Set[test02].size(); for(__typeof(Set[test01].begin()) it=Set[test01].begin();it!=Set[test01].end();it++){ if(Set[test02].find(*it)==Set[test02].end()){ u++; }else{ n++; } } printf("%.2lf%%\n",(double)n/u*100); } } }