• [原创]百度之星2009初赛第二场第四题解答


    百度之星2009程序设计大赛 初赛第二场第四题解答


    题目:

    4. 我的地盘 (350分)

    题目描述

    百度公司的员工们在工作之余,经常以产品组为单位组织一些活动,包括吃大餐、春游秋游、公益活动、唱KTV、看电影、体育比赛等。这些活动有一个专业的名字,叫做team building,我们也亲切的称之为“bui”。

    bui

    最近,地图产品组刚刚完成一个大项目,大家决定大bui一场。一阵七嘴八舌后,很多内容被提了出来,最终确定先打乒乓球,然后吃饭,最后K歌。问题是,谁也不知道有什么地方可以同时满足这三个需求。

    不过没有什么问题可以难倒我们的工程师。很快,就有人写出了程序,为大家找到了合适的地点。

    地图覆盖之处,皆为我的地盘。你想挑战一下我们的工程师吗?想为我们找出更合适的地点吗?那就来吧。

    输入格式

    第1行是一个整数k,表示某范围内所有的POI(Point of Interest)点数量,后续k行每行用5个字段描述一个POI点。它们的含义和格式如下表:

    内容 数据格式 数据范围

    POI编号 Int,唯一 [0,231-1]

    POI类型 字符串 0-16字节(不超过15种类型)

    POI级别 Int 0-5(越大表示越高级)

    POI经度 Double [0,180],6位有效精度

    POI纬度 Double [0,180],6位有效精度

    需要注意的是这里的经纬度跟通常的经纬度范围是不一样的

    随后是一个整数n(0 < n <= 20),表示共n组查询。以下n行,每行表示一组查询,格式为:

    POI类型1 POI类型2 POI类型3 最低级别 最高级别

    分别表示三个bui地点各自的类型、最低级别和最高级别。

    输出格式

    对于每组查询”t1 t2 t3 min max”,输出三个POI编号p1、p2、p3,满足:

    •p1、p2、p3的类型分别为t1、t2和t3。

    •p1、p2、p3的级别不小于min,不大于max。

    •p1、p2、p3的两两欧几里得距离之和应尽量小。

    输入数据保证至少存在一个解。

    样例输入

    5

    1 休闲娱乐 3 11.122843 12.431021

    2 餐饮服务 2 13.384021 10.230425

    3 旅游景点 3 12.234492 9.234268

    4 休闲娱乐 5 20.242391 39.304233

    5 教育机构 1 42.243292 67.232065

    1

    休闲娱乐 餐饮服务 旅游景点 0 5

    样例输出

    1 2 3

    测试数据

    点击此处下载一份POI数据。所有测试点中的POI数据都基于此数据生成。可能的变动包括:

    •修改POI编号

    •对经纬度加入随机干扰(变化不会超过1%)。

    •修改POI类别和级别

    •加入不超过1%的新点,各项属性均完全随机

    共20组测试点,其中第i个测试点包含i组查询。1 <= i <= 20

    注意事项

    •对于每个测试点,设已知最优解为D,则不超过1.05D的任意解均是可以接受的。

    •请不要把离线计算的结果保存在源代码中(例如,直接把某些输入的答案保存在常量数组中,读取输入后直接输出),否则本题得0分。

    分析:由于不需要求最优解,因此不用全部遍历,使用贪心法寻找离 当前已选择点集合 最近的点,不过没有测试是否最优,比赛的时候提交的是没有优化的代码,比完后又花了半个钟才完成了以下代码,感觉编码速度还是有待加强。

    我的水平只能弄出这样的结果了,不过应该还有更优的解法。

    #include <stdio.h>
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    struct POI
    {
        int id;
        string kind;
        int level;
        double x;
        double y;
    };
    int main()
    {
        int k,n,i,j;
        vector<POI> all;
        scanf("%d",&k);
        for(i=0;i<k;i++)
        {
            POI temp;
            cin>>temp.id>>temp.kind>>temp.level>>temp.x>>temp.y;
            all.push_back(temp);
        }
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            string t[3];
            int min,max;
            cin>>t[0]>>t[1]>>t[2]>>min>>max;
            int index[3]={0},totalindex[3]={0};
            index[0]=-1;
            double totalmindis = 360*360*3;
            //方法:第一个POI选择所有可能的值,然后对每个可能的第一个POI,选择离他最近的第二个POI,
            //选好第二个后,选择离前面两个距离之和最小的那个为第三个POI,
            //选好三个后计算总距离,如果小于前一个解则更新解,终结条件是找到所有可能的第一个POI

            while(index[0]<(int)all.size())
            {
                double curtotal = 0;
                for(j=0;j<3;j++)
                {
                    double mindis1 = 360*360;
                    double mindis2 = 360*360*2;
                    for(k=0;k<all.size();k++)
                    {
                        if(t[j]==all[k].kind&&all[k].level>=min&&all[k].level<=max)
                        {
                            //第一个POI
                            if(j==0)
                            {
                                if(k>index[0])
                                {
                                    index[j] = k;
                                    break;
                                }
                            }
                            //第二个POI
                            else if(j==1)
                            {
                                double dis = (all[k].x-all[index[j-1]].x)*(all[k].x-all[index[j-1]].x)+
                                    (all[k].y-all[index[j-1]].y)*(all[k].y-all[index[j-1]].y);
                                if(dis<mindis1)
                                {
                                    index[j]=k;
                                    mindis1 = dis;
                                }
                            }
                            //第三个POI
                            else if(j==2)
                            {
                                double dis=0;
                                int t;
                                for(t=0;t<j;t++)
                                {
                                    dis += (all[k].x-all[index[t]].x)*(all[k].x-all[index[t]].x)+
                                        (all[k].y-all[index[t]].y)*(all[k].y-all[index[t]].y);
                                }
                                if(dis<mindis2)
                                {
                                    index[j]=k;
                                    mindis2 = dis;
                                }
                            }
                        }
                    }
                    //计算当前的总距离
                    if(j==1)
                        curtotal += mindis1;
                    if(j==2)
                        curtotal += mindis2;
                    //判断是否已经试过第一个POI的所有可能
                    if(j==0&&k==all.size())
                        index[j]=k;
                }
                if(curtotal<totalmindis&&index[0]!=all.size())
                {
                    totalindex[0] = index[0];
                    totalindex[1] = index[1];
                    totalindex[2] = index[2];
                    totalmindis = curtotal;
                }
            }
            cout<<all[totalindex[0]].id<<" "<<all[totalindex[1]].id<<" "<<all[totalindex[2]].id<<endl;
        }
        return 0;
    }

    弄了一组测试数据:
    15
    1 休闲娱乐 5 20.242391 39.304233
    2 餐饮服务 2 13.384021 10.230425
    3 旅游景点 3 12.234492 9.234268
    4 休闲娱乐 3 11.122843 12.431021
    5 教育机构 1 42.243292 67.232065
    6 餐饮服务 2 113.054282 29.098546357
    7 旅游景点 5 116.834988 39.952290455
    8 旅游景点 5 113.166512 22.922672903
    9 餐饮服务 2 113.054439 29.0987291154
    10 文化教育 3 113.282175 23.201096485
    11 综合商场 5 113.166579 22.923254613
    12 金融行业 1 117.219020 36.500982133
    13 文化教育 5 113.755876 39.739886517
    14 综合商场 3 114.120915 36.1436581215
    15 金融行业 5 104.688191 30.1736361401
    5
    休闲娱乐 餐饮服务 旅游景点 0 5
    餐饮服务 休闲娱乐 旅游景点 0 5
    金融行业 文化教育 综合商场 0 5
    旅游景点 餐饮服务 金融行业 0 5
    文化教育 餐饮服务 金融行业 0 5

    我的答案是:
    4 2 3
    2 4 3
    12 13 14
    7 9 12
    13 9 12
  • 相关阅读:
    使用QT实现一个简单的登陆对话框(纯代码实现C++)
    vivado + hdmi+ddr3(2)--------基于VIVADO的DDR3三个时钟
    Verilog实现之任意分频电路
    Verilog实现之异步fifo
    vivado + hdmi+ddr3(1)--------HDMI接口协议介绍及实现
    verilog实现之同步FIFO
    FPGA 开发基础---------格雷码转二进制
    verilog之生成语句
    verilog 实现之RAM
    FPGA开发基础--------Handshake Protocol握手协议(1)
  • 原文地址:https://www.cnblogs.com/absolute8511/p/1649573.html
Copyright © 2020-2023  润新知