邮局选址问题--分治

【问题描述】
在一个按照东西和南北方向划分成规整街区的城市里,n个居民点散乱地分布在不同的街区中。用x坐标表示东西向,用y坐标表示南北向。各居民点的位置可以由坐标(x,y)表示。要求:为建邮局选址,使得n个居民点到邮局之距离的总和最小。以文件输入形式进行测试。
【思路】
运用分治思想。将居民点的坐标从输入文件中获取到并且存入两个一维数组x[]和y[]中。利用快速排序分别将两个数组进行排序,排序的时候是确定一个主元,把数组分成大于主元和小于主元的两个部分,然后分别递归调用快排的方法进行排序,一直到有序,这就运用到了分治的思想。分别取排好序的两个数组的中位数,然后用数组的每一个元素减去中位数取绝对值再相加得到最短距离。
【运行环境】CodeBlocks
【编程语言】C++
【运行过程】
首先,将输入数据分七组填入input_assign01_01-input_assign01_07文件中。
其次,在CodeBlocks中编译运行该程序,程序读取到每个输入文件的内容。
最后,按程序中的输出格式按每组测试数据将每个文件中的居民点到邮局的最短距离显示出来。
【测试数据】
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
【源代码】

#include<iostream>
#include<cmath>
#include <fstream>
#include<string>
#include <cstdlib>

using namespace std;

int N;                          //N是居民点的个数
int x[1000];                    //居民点的x坐标数组
int y[1000];                    //居民点的y坐标数组

void input(string fn)           //输入数据文件函数
{
      ifstream fin(fn.c_str()); //打开第 i 个文件
      fin>>N;                   //读取居民点个数
      for(int i=0;i<N;i++)      //循环读取每个居民点的坐标值
      {
         fin>>x[i]>>y[i];       //读取居民点的坐标值,放在居民点的坐标数组中
      }
      fin.close();              //文件读取完之后关闭文件

}

int divide(int m[], int left, int right)    //left为数组第一个元素,right是数组最后一个元素
{
    int x = m[right];                       //输入数据的最后一个元素是主元
    int i = left - 1;                       //i是最后一个小于主元的数的下标
    for (int j = left; j < right; j++)      //遍历下标由left到right-1的数
    {
        if (m[j] < x)                       //如果数小于主元的话就将i向前移动一个位子,然后交换j和i所分别指向的数
        {
            int temp;
            i++;
            temp = m[i];
            m[i] = m[j];
            m[j] = temp;
        }
    }

    //循环结束后下标为从left到i(包括i)的数都是小于x的数,接下来将主元和i+1位置上面的数进行交换
    m[right] = m[i + 1];
    m[i + 1] = x;
    return i + 1;
}

void QSort(int a[], int left, int right)              //运用分治思想
{
    if (left < right)
    {
        int p = divide(a, left, right);
        QSort(a, left, p - 1);
        QSort(a, p + 1, right);
    }
}

void getMinSumDistance(int *x,int *y,int N)            //求距离总和最小值
{
        int dx;                                        //x坐标中位数
        int dy;                                        //y坐标中位数
        int Distance=0;                                //n个居民点到该邮局的距离的总和
        QSort(x,0,N-1);
        QSort(y,0,N-1);
        dx=x[N/2];                                     //求X坐标中位数
        dy=y[N/2];                                     //求Y坐标中位数
        for(int i=0;i<N;i++)                           //计算距离总和
        Distance += abs(x[i]-dx)+abs(y[i]-dy);
        cout<<"all居民点到邮局的MinSumDistance:"<<Distance<<endl;     //输出最短距离

}

int main()
{
       int i;
       string fn, st1="input_assign01_0",st2="1234567",st3=".txt";     //拼出第 i 个文件的文件名

       for(i=1;i<=7;i++)
       {
            cout<<"第"<<i<<"组data"<<endl;
            fn=st1+st2.substr(i-1,1)+st3;
            input(fn);
            getMinSumDistance(x,y,N);
       }
       system("pause");
       return 0;

}


【运行结果】
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/JSTFighting123/article/details/83240086
今日推荐