zoukankan      html  css  js  c++  java
  • 2013数据结构课程设计之便利店选址(暴力枚举和随机函数两种做法)

    [问题描述]

    某小区决定在小区内部建一家便利店,现小区内部共有八栋楼,它们的地理坐标分别为:(10,20) (30,34) (19,25) (38,49.1) (9,38.1) (2,34) (5,8) (29,48)。同时,其中的住户人数分别为:30, 45, 28, 8, 36, 16, 78, 56。为了方便更多的住户购物,要求实现总体最优,请问便利店应该建立在哪里?

    【提示】

    1)便利店无论选址何处,八栋楼的居民均可直接到达,即八栋楼与便利店均相邻,且距离为直线距离;

    2)八栋楼的居民人数为权重,应该方便大多数人,实现总体最优。


    先是暴力找点的方法。


    解题思路:自己开始想的就是暴力枚举,先找大范围,再找小范围。做这个题目就想到了的warmup2的1002题,但当时就是A不了。思路很简单,一步步地精确范围。先把整个地方划分成10*10的方格,再在里面找哪个最小,然后继续10*10每次都这样划分,精度确定跳出循环即可。详解见代码。


    代码:

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #include<ctime>
    using namespace std;
    int n; //n栋楼
    double minx,miny,maxx,maxy,px,py;  //找到四个边界
    double ansx,ansy,sum;  //最后的结果
    struct mq
    {
        double x;
        double y;
        int peo;
    };
    mq node[1005];
    
    double cal(double px,double py)  //计算值
    {
        int i;
        double sum=0;
        for(i=0;i<n;i++)
            sum+=sqrt((px-node[i].x)*(px-node[i].x)+(py-node[i].y)*(py-node[i].y))*node[i].peo;
        return sum;
    }
    
    void solve()
    {
         double i,j;
         double fenx=maxx-minx;  //把x分成若干份
         double feny=maxy-miny;  //把y分成若干份
    
         while(fenx>0.01&&feny>0.01)  //暴力找点
         {
            fenx/=10.0,feny/=10.0;
            for(i=minx;i<=maxx;i+=fenx)
                for(j=miny;j<=maxy;j+=feny)
                {
                     double tmp=cal(i,j);
                     if(tmp<sum)
                     {
                         sum=tmp;
                         ansx=i;
                         ansy=j;
                     }
                }
            minx=ansx-fenx;
            miny=ansy-feny;
            maxx=ansx+fenx;
            maxy=ansy+feny;
         }
    }
    
    int main()
    {
        int i;
        //freopen("input.txt","r",stdin);
        //freopen("output.txt","w",stdout);
        while(~scanf("%d",&n))  //n栋楼
        {
            scanf("%lf%lf%d",&node[0].x,&node[0].y,&node[0].peo);
            minx=maxx=node[0].x; miny=maxy=node[0].y;
            //找到四个边界
            for(i=1;i<n;i++)
            {
                scanf("%lf%lf%d",&node[i].x,&node[i].y,&node[i].peo);
                if(node[i].x<minx) minx=node[i].x;
                if(node[i].x>maxx) maxx=node[i].x;
                if(node[i].y<miny) miny=node[i].y;
                if(node[i].y>maxy) maxy=node[i].y;
            }
    
            sum=100000000;
            solve();
            cout<<"便利店选址坐标为:"<<endl;
            cout<<"x: "<<ansx<<"   "<<"y: "<<ansy<<endl;
            cout<<"最优解为: "<<sum<<endl;
        }
        return 0;
    }
    
    /*
    8
    10 20 30
    30 34 45
    19 25 28
    38 49.1 8
    9 38.1 36
    2 34 16
    5 8 78
    29 48 56
    便利店选址坐标为:
    x: 16.5404   y: 27.4362
    最优解为: 5146.85
    */
    


    然后就是LCM说的随机算法,也没想到那一块,被他一说是有些道理,但是点的范围一扩大的话,就没那么准确了。

    随机算法,我是直接采用的随机数然后%lenth,区间宽度,相当于0~lenth-1。随机函数对范围要求比较严格吧,范围如果太大,随机也没用了。具体实现见代码:

    代码:

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #include<ctime>
    using namespace std;
    int n; //n栋楼
    struct mq
    {
        double x;
        double y;
        int peo;
    };
    mq node[1005];
    
    double cal(double px,double py)  //计算值
    {
        int i;
        double sum=0;
        for(i=0;i<n;i++)
            sum+=sqrt((px-node[i].x)*(px-node[i].x)+(py-node[i].y)*(py-node[i].y))*node[i].peo;
        return sum;
    }
    int main()
    {
        int i;
        freopen("input.txt","r",stdin);
        freopen("output.txt","w",stdout);
        double minx,miny,maxx,maxy,px,py;  //找到四个边界
        double ansx,ansy;  //最后的结果
        while(~scanf("%d",&n))  //n栋楼
        {
            scanf("%lf%lf%d",&node[0].x,&node[0].y,&node[0].peo);
            minx=maxx=node[0].x; miny=maxy=node[0].y;
            //找到四个边界
            for(i=1;i<n;i++)
            {
                scanf("%lf%lf%d",&node[i].x,&node[i].y,&node[i].peo);
                if(node[i].x<minx) minx=node[i].x;
                if(node[i].x>maxx) maxx=node[i].x;
                if(node[i].y<miny) miny=node[i].y;
                if(node[i].y>maxy) maxy=node[i].y;
            }
    
            minx*=100,maxx*=100,miny*=100,maxy*=100;  //边界扩大一百倍
            //找到边界了就可以随机了
            int lenx,leny;
            lenx=ceil(maxx-minx),leny=ceil(maxy-miny);
            double sum=1000000000;
            srand((unsigned)time(NULL));  //播种
            for(i=1;i<=500000;i++) //随机50W次
            {
                px=rand()%lenx+minx;
                py=rand()%leny+miny;
                px/=100.0;
                py/=100.0;
                double tmp=cal(px,py);
                if(tmp<sum)
                {
                    sum=tmp;
                    ansx=px;
                    ansy=py;
                }
            }
            cout<<"便利店选址坐标为:"<<endl;
            cout<<"x: "<<ansx<<"   "<<"y: "<<ansy<<endl;
            cout<<"最优解为: "<<sum<<endl;
        }
        return 0;
    }
    
    /*
    8
    10 20 30
    30 34 45
    19 25 28
    38 49.1 8
    9 38.1 36
    2 34 16
    5 8 78
    29 48 56
    便利店选址坐标为:
    x: 16.56   y: 27.44
    最优解为: 5146.85
    */
    


  • 相关阅读:
    Android的NDK开发(5)————Android JNI层实现文件的read、write与seek操作
    android Context
    android 控件放在 listview 的下方 并且在 屏幕底部
    android Activity 布局 和 控件属性
    有关vtun和虚拟网卡要做的实验
    android xml pull 解析 豆瓣书籍
    android UI设计之 背景透明色 项目资源文件关系
    android 资源引用 自定义标题栏
    真机调试Unable to open sync connection!
    C++ 编译预处理
  • 原文地址:https://www.cnblogs.com/james1207/p/3318109.html
Copyright © 2011-2022 走看看