• hdu 4995(离散化下标+模拟)


    Revenge of kNN

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 584    Accepted Submission(s): 136


    Problem Description
    In pattern recognition, the k-Nearest Neighbors algorithm (or k-NN for short) is a non-parametric method used for classification and regression. In both cases, the input consists of the k closest training examples in the feature space.
    In k-NN regression, the output is the property value for the object. This value is the average of the values of its k nearest neighbors.
    ---Wikipedia

    Today, kNN takes revenge on you. You have to handle a kNN case in one-dimensional coordinate system. There are N points with a position Xi and value Vi. Then there are M kNN queries for point with index i, recalculate its value by averaging the values its k-Nearest Neighbors. Note you have to replace the value of i-th point with the new calculated value. And if there is a tie while choosing k-Nearest Neighbor, choose the one with the minimal index first.
     
    Input
    The first line contains a single integer T, indicating the number of test cases.

    Each test case begins with three integers N, M and K, in which K indicating the number of k-Nearest Neighbors. Then N lines follows, each line contains two integers Xi and Vi. Then M lines with the queried index Qi follows.

    [Technical Specification]
    1. 1 <= T <= 5
    2. 2<=N<= 100 000, 1<=M<=100 000
    3. 1 <= K <= min(N – 1, 10)
    4. 1 <= Vi <= 1 000
    5. 1 <= Xi <= 1 000 000 000, and no two Xi are identical.
    6. 1 <= Qi <= N
     
    Output
    For each test case, output sum of all queries rounded to six fractional digits.
     
    Sample Input
    1 5 3 2 1 2 2 3 3 6 4 8 5 8 2 3 4
     
    Sample Output
    17.000000
    做这题让我知道了如何解决一个很常见但是也很难想的问题:一个数组如果排序后被打乱了,知道它原来的位置,如何对应出现在的位置?
    题意:X轴上有 n 个点,每个点都有个初始位置和权值(这些位置是杂乱无章的),现在给m次询问:每次询问第 i 个给出的点,找出离他最近的 k 个点,然后将 k 个点的权值相加取平均值赋值给当前询问的点,输出的最终答案就是这m 次询问每次询问的平均值之和。还有就是关于 k 个点的选取,当距离相同时,选择给出顺序小的。
    题解:由于要找到邻居,排序是无疑的,但是询问却是询问的以前的位置。排完序之后如何找到原来的位置??循环?不行,10^5次询问每次找点也要10^5,肯定会超时?这时我们可以利用一个数组来记录排完序后元素原来的位置。但是,元素的下标是从 1 <= Xi <= 1 000 000 000,数组肯定存不下,怎么办?离散化呗,这样寻找的时间就变成 O(1)了。
    可能有人不懂离散化后数组存的意思,这里举个例子:
    原来的X轴分布假设为:
    3 1 2 100 99
    我们记录一下每个Xi 出现的位置 3(1) 1(2) 2(3) 100(4) 99(5)
    排个序: 1(2) 2(3) 3(1) 99(5) 100(4)
    弄个数组将括号里面的数表示成下标分别赋值给 1-5  a[2]=1 a[3]=2 a[1]=3 a[5]=4 a[4]=5
    然后对应查询,假设我们查询初始位置是第 4 位的那个 Xi=100,对应排完序后的数组的位置是 a[4] = 5 而新的数组第5个数字等于100!!是不是很神奇,这就是离散化的好处了.不懂我说的同学可以看下acdreamer大神的博客:http://blog.csdn.net/acdreamers/article/details/8520096
     
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    const int N = 111111;
    struct Node{
        LL x;
        int id1;
        double v;
    }node[N];
    int idx[N];
    int cmp(Node a,Node b){
        return a.x<b.x;
    }
    int main()
    {
        int tcase,n,m,k,x;
        scanf("%d",&tcase);
        while(tcase--)
        {
            scanf("%d%d%d",&n,&m,&k);
            for(int i=1;i<=n;i++){
                scanf("%lld%lf",&node[i].x,&node[i].v);
                node[i].id1 = i;
            }
            sort(node+1,node+1+n,cmp);
            for(int i=1;i<=n;i++){
                idx[node[i].id1] = i;
            }
            double sum = 0;
            while(m--){
                int id;
                scanf("%d",&id);
                int now = idx[id];
                double avg = 0;
                int l = now-1,r = now+1;
                for(int i=1;i<=k;i++){
                    if(l>=1&&r<=n){
                        LL dis1 = node[now].x - node[l].x;
                        LL dis2 = node[r].x - node[now].x;
                        if(dis1<dis2){
                            avg+=node[l--].v;
                        }else if(dis1>dis2){
                            avg+=node[r++].v;
                        }else { ///相等的话按照邻居原来的下标进行选择
                            int ori_l = node[l].id1;
                            int ori_r = node[r].id1;
                            if(ori_l<ori_r) {
                                avg+=node[l--].v;
                            }else{
                                avg+=node[r++].v;
                            }
                        }
                    }else if(l>=1){
                        avg+=node[l--].v;
                    }else if(r<=n){
                        avg+=node[r++].v;
                    }
                }
                /*  ///不知道WA的原因
                int l=1,r=1;
                for(int i=1;i<=k;i++){
                    if(now-l>=1&&now+r<=n){
                        LL dis1 = node[now].x - node[now-l].x;
                        LL dis2 = node[now+r].x - node[now].x;
                        if(dis1<dis2){
                            avg+=node[now-l].v;
                            l++;
                        }else if(dis1>dis2){
                            avg+=node[now+r].v;
                            r++;
                        }else { ///相等的话按照邻居原来的下标进行选择
                            int ori_l = node[now+l].id1;
                            int ori_r = node[now+r].id1;
                            if(ori_l<ori_r) {
                                avg+=node[now-l].v;
                                l++;
                            }else{
                                avg+=node[now+r].v;
                                r++;
                            }
                        }
                    }else if(now-l>=1){
                        avg+=node[now-l].v;
                        l++;
                    }else if(now+r<=n){
                        avg+=node[now+r].v;
                        r++;
                    }
                }*/
                node[now].v = avg/k;
                sum+=avg/k;
            }
            printf("%.6lf
    ",sum);
        }
        return 0;
    }
  • 相关阅读:
    vbs下载文件
    变量名自动变化
    VBS获得随机数,截图函数
    VBS定时关闭的弹窗
    VBS操作剪切板
    手动关闭端口
    win7,xp通用的打开文件浏览对话框的方法
    QTP全选页面的复选框
    SVN的使用
    工作中用到的前端内容整理
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5648533.html
Copyright © 2020-2023  润新知