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)八栋楼的居民人数为权重,应该方便大多数人,实现总体最优。

 

下面是第一次写的做法  不精确

解题思路:对便利店的x 和y 分别使用三分法   先用x三分确定y  再用y三分确定x 代码如下:

 

#include <iostream>
#include <cmath>
using namespace std;

struct building
{
    double x;
    double y;
    double value;
};

building bd[1000];

int n;//n栋楼
double minx,maxx,miny,maxy;//记录各栋楼的区域
double midx,mmidx,midy,mmidy;
double result_x,result_y,sum = 100000;//最后结果

double dis(double x,double y)//计算距离
{
    double sum= 0;
    for(int i = 0;i < n;i++)
    {
        sum += sqrt((x - bd[i].x)*(x - bd[i].x) + (y - bd[i].y)*(y - bd[i].y))*bd[i].value;
    }
    return sum;
}

void D_Divide()//三分法求位置
{
    midx = (minx + maxx)/2;
    mmidx = (midx + maxx)/2;
    midy = (miny + maxy)/2;
    mmidy = (midy + maxy)/2;

    while((maxx-minx) > 0.01)
    {
        while((maxy-miny)>0.01)
        {
            if(dis(midx,midy) > dis(midx,mmidy))
                miny = midy;
            else
                maxy = mmidy;
            midy = (miny + maxy)/2;
            mmidy = (midy + maxy)/2;
        };
        if(dis(midx,midy) > dis(mmidx,midy))
            minx = midx;
        else
            maxx = mmidx;
        midx = (minx + maxx)/2;
        mmidx = (midx + maxx)/2;
    };
    result_x = midx;
    result_y = midy;
    sum = dis(result_x,result_y);
}
int main()
{
    cout<<"请输入楼的数量:";
    cin>>n;

    cout<<"\n请输入各楼x y 权值"<<endl;
    minx = maxx = miny = maxy = 0;

    for(int i = 0;i < n;i++)
    {
        cin>>bd[i].x>>bd[i].y>>bd[i].value;
        if(bd[i].x < minx)
            minx = bd[i].x;
        if(bd[i].x > maxx)
            maxx = bd[i].x;
        if(bd[i].y < minx)
            miny = bd[i].y;
        if(bd[i].y > maxx)
            maxy = bd[i].y;
    }
    D_Divide();

    cout<<"\n便利店选址坐标为:"<<endl;
    cout<<"x: "<<result_x<<"   "<<"y: "<<result_y<<endl;
    cout<<"\n最优解为: "<<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.5379   y:27.573
最优解 ;5146.96
*/


以上解法有一点误差    因为每次 if(dis(midx,midy) > dis(midx,mmidy)) 时使用的都是midx 的最佳y  下面还把这样求得的y当做了mmidx的最佳y

 

下面是改正后的代码
 

#include <iostream>
#include <cmath>
using namespace std;

struct building
{
    double x;
    double y;
    double value;
};

building bd[1000];

int n;//n栋楼
double minx,maxx,miny,maxy;//记录各栋楼的区域
double midx,mmidx,midy,mmidy;
double result_x,result_y,sum = 100000;//最后结果

double dis(double x,double y)//计算距离
{
    double sum= 0;
    for(int i = 0;i < n;i++)
    {
        sum += sqrt((x - bd[i].x)*(x - bd[i].x) + (y - bd[i].y)*(y - bd[i].y))*bd[i].value;
    }
    return sum;
}

double Divide_y(double x)//三分法求y
{
    double right_y,left_y;

    right_y = maxy;
    left_y = miny;

    midy = (left_y + right_y)/2;
    mmidy = (midy + right_y)/2;

    while((right_y-left_y)>0.01)
    {
        if(dis(x,midy) > dis(x,mmidy))
            left_y = midy;
        else
            right_y = mmidy;
        midy = (left_y + right_y)/2;
        mmidy = (midy + right_y)/2;
    };
    return dis(x,midy);
}
void D_Divide()//三分法求x
{
    midx = (minx + maxx)/2;
    mmidx = (midx + maxx)/2;

    while((maxx-minx) > 0.01)
    {
        if(Divide_y(midx) > Divide_y(mmidx))
            minx = midx;
        else
            maxx = mmidx;
        midx = (minx + maxx)/2;
        mmidx = (midx + maxx)/2;
    };
    result_x = midx;
    result_y = midy;
    sum = dis(result_x,result_y);
}
int main()
{
    cout<<"请输入楼的数量:";
    cin>>n;

    cout<<"\n请输入各楼x y 权值"<<endl;
    minx = maxx = miny = maxy = 0;

    for(int i = 0;i < n;i++)
    {
        cin>>bd[i].x>>bd[i].y>>bd[i].value;
        if(bd[i].x < minx)
            minx = bd[i].x;
        if(bd[i].x > maxx)
            maxx = bd[i].x;
        if(bd[i].y < minx)
            miny = bd[i].y;
        if(bd[i].y > maxx)
            maxy = bd[i].y;
    }
    D_Divide();

    cout<<"\n便利店选址坐标为:"<<endl;
    cout<<"x: "<<result_x<<"   "<<"y: "<<result_y<<endl;
    cout<<"\n最优解为: "<<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.5406   y:27.4346
最优解 ;5146.85
*/

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值