[原创]百度之星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

posted on 2009-05-31 22:02  absolute  阅读(326)  评论(0编辑  收藏  举报

导航