L2-005. 集合相似度


題目鏈接:https://www.patest.cn/contests/gplt/L2-005

L2-005. 集合相似度

時間限制
400 ms
內存限制
65536 kB
代碼長度限制
8000 B
判題程序
Standard
作者
陳越

給定兩個整數集合,它們的相似度定義為: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);
        }
    }
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM