邮局选址问题
2011-03-17 17:19
260 查看
邮局选址问题
★问题描述:
在一个按照东西和南北方向划分成规整街区的城市里,n个居民点散乱地分布在不同的
街区中。用x 坐标表示东西向,用y坐标表示南北向。各居民点的位置可以由坐标(x,y)表示。
街区中任意2 点(x1,y1)和(x2,y2)之间的距离可以用数值|x1-x2|+|y1-y2|度量。
居民们希望在城市中选择建立邮局的最佳位置,使n个居民点到邮局的距离总和最小。
★编程任务:
给定n 个居民点的位置,编程计算n 个居民点到邮局的距离总和的最小值。
★数据输入:
由文件input.txt 提供输入数据。文件的第1 行是居民点数n,1£n£10000。接下来n 行
是居民点的位置,每行2 个整数x 和y,-10000£x,y£10000。
★结果输出:
程序运行结束时,将计算结果输出到文件output.txt 中。文件的第1 行中的数是n 个居
民点到邮局的距离总和的最小值。
★输入文件示例 输出文件示例
Input.txt output.txt
5
1 2
2 2
1 3
3 -2
3 3 10
运行环境: Windows XP,(开发环境:VC6.0)
运行过程说明: 本实验设计并实现了三种算法,
双击postOfficeQuickSort.exe或postOfficeRandomSelect.exe或postOfficeTimeLinearSelect.exe
按照提示输入 数据文件:input_assign01_xx.dat,每次输入一个文件名,回车,即可在output.txt中查看输出结果。
算法设计(包括算法设计过程中相关内容的说明、数据结构的选择、 算法详细描述及算法分析):
●1.设计说明:
设给定的n个居民点的位置坐标为:(x0,y0),(x1,y1),...,(xn-1,yn-1)。
设x0,x1,...,xn-1的中位数为median(x) 。通过进一步观察可知, median(x) 是的最优解。
邮局选址问题实际上是求中位数的问题。
●2.算法设计:
2.1数据结构:
将文件中读入的居民点坐标存放于数组中,横纵坐标各保存在一个数组中。
2.2算法描述:
postOffice()
{
int dx = getMidX(); //求横坐标中位数
int dy = getMidY(); //求纵坐标中位数
for(int i=0;i<n;i++) //计算距离总和
Distance += abs(x[i]-dx)+abs(y[i]-dy);
}
求中位数的过程用三种算法进行了设计:
快速排序选择中位数
快速排序算法qsort将n个居民点的x 坐标和y坐标分别排序后,计算出中位数median(x)和median( y),由此容易求得n个居民点到邮局的距离总和的最小值。
//--------------------------------------------
//求居民点到邮局的距离和的最小值
//prameter:横坐标数组,纵坐标数组,数组大小
//return:居民点到邮局的距离和的最小值
//--------------------------------------------
int postOffice(int * x, int * y, int size)
{
qsort(x,size,sizeof(int),compare); //快排数组x
qsort(y,size,sizeof(int),compare);
int min = getMinSumDistance(x,size) + getMinSumDistance(y,size);
//居民点到邮局的距离和的最小值
return min;
}
(2)随机选择法求中位数
用随机选择算法randomizedSelect 选择一个基准数,以此进行二分划分,计算出中位数median(x) 和median( y),然后计算n个居民点到邮局的距离总和的最小值。
//--------------------------------------------
//求居民点到邮局的距离和的最小值
//prameter:横坐标数组,纵坐标数组,数组大小
//return:居民点到邮局的距离和的最小值
//--------------------------------------------
int postOffice(int * x, int * y, int size)
{
int minX = randomizedSelect(x, 0, size - 1,(size + 1)/2);
int minY = randomizedSelect(y, 0, size - 1,(size + 1)/2);
int min = getMinSumDistance(x, size, minX) + getMinSumDistance(y, size, minY);
return min;
}
(3)线性时间选择求中位数
用最坏情况下的线性时间选择算法select计算出中位数median(x)和
median( y),然后计算n个居民点到邮局的距离总和的最小值。
//--------------------------------------------
//求居民点到邮局的距离和的最小值
//prameter:横坐标数组,纵坐标数组,数组大小
//return:居民点到邮局的距离和的最小值
//--------------------------------------------
int postOffice(int * x, int * y, int size)
{
int minX = select(x, 0, size - 1,(size + 1)/2);
int minY = select(y, 0, size - 1,(size + 1)/2);
int min = getMinSumDistance(x, size, minX) + getMinSumDistance(y, size, minY);
return min;
}
最坏情况下的线性时间选择算法select:
(1)将n个输入元素划分成n/5的上界 个组,每组5个元素,只可能有一个组不是5个元素。用冒泡排序算法,将每组中的元素排好序,并取出每组的中位数,共n/5的上界 个。
(2)找出这n/5的上界个元素的中位数。如果n/5的上界是偶数,就找它的2个中位数中较大的一个,以这个元素作为划分基准。
2.3算法分析
快速排序选择中位数
快排时间复杂度:O(nlogn),求距离和:O(n)
总复杂度:O(nlogn)。
(2)随机选择法求中位数
最坏情况下,randomizedSelect的时间复杂度是:O(n2),平均时间为O(n)
故时间复杂度为:O(n2)。
线性时间选择求中位数
最坏情况下,select算法时间复杂度为O(n),求距离和:O(n)
总复杂度:O(n)。
以上三种算法的空间复杂度均为O(n)。
其他说明:
本算法 设计说明部分 部分内容(公式)来自互联网
★问题描述:
在一个按照东西和南北方向划分成规整街区的城市里,n个居民点散乱地分布在不同的
街区中。用x 坐标表示东西向,用y坐标表示南北向。各居民点的位置可以由坐标(x,y)表示。
街区中任意2 点(x1,y1)和(x2,y2)之间的距离可以用数值|x1-x2|+|y1-y2|度量。
居民们希望在城市中选择建立邮局的最佳位置,使n个居民点到邮局的距离总和最小。
★编程任务:
给定n 个居民点的位置,编程计算n 个居民点到邮局的距离总和的最小值。
★数据输入:
由文件input.txt 提供输入数据。文件的第1 行是居民点数n,1£n£10000。接下来n 行
是居民点的位置,每行2 个整数x 和y,-10000£x,y£10000。
★结果输出:
程序运行结束时,将计算结果输出到文件output.txt 中。文件的第1 行中的数是n 个居
民点到邮局的距离总和的最小值。
★输入文件示例 输出文件示例
Input.txt output.txt
5
1 2
2 2
1 3
3 -2
3 3 10
运行环境: Windows XP,(开发环境:VC6.0)
运行过程说明: 本实验设计并实现了三种算法,
双击postOfficeQuickSort.exe或postOfficeRandomSelect.exe或postOfficeTimeLinearSelect.exe
按照提示输入 数据文件:input_assign01_xx.dat,每次输入一个文件名,回车,即可在output.txt中查看输出结果。
算法设计(包括算法设计过程中相关内容的说明、数据结构的选择、 算法详细描述及算法分析):
●1.设计说明:
设给定的n个居民点的位置坐标为:(x0,y0),(x1,y1),...,(xn-1,yn-1)。
设x0,x1,...,xn-1的中位数为median(x) 。通过进一步观察可知, median(x) 是的最优解。
邮局选址问题实际上是求中位数的问题。
●2.算法设计:
2.1数据结构:
将文件中读入的居民点坐标存放于数组中,横纵坐标各保存在一个数组中。
2.2算法描述:
postOffice()
{
int dx = getMidX(); //求横坐标中位数
int dy = getMidY(); //求纵坐标中位数
for(int i=0;i<n;i++) //计算距离总和
Distance += abs(x[i]-dx)+abs(y[i]-dy);
}
求中位数的过程用三种算法进行了设计:
快速排序选择中位数
快速排序算法qsort将n个居民点的x 坐标和y坐标分别排序后,计算出中位数median(x)和median( y),由此容易求得n个居民点到邮局的距离总和的最小值。
//--------------------------------------------
//求居民点到邮局的距离和的最小值
//prameter:横坐标数组,纵坐标数组,数组大小
//return:居民点到邮局的距离和的最小值
//--------------------------------------------
int postOffice(int * x, int * y, int size)
{
qsort(x,size,sizeof(int),compare); //快排数组x
qsort(y,size,sizeof(int),compare);
int min = getMinSumDistance(x,size) + getMinSumDistance(y,size);
//居民点到邮局的距离和的最小值
return min;
}
(2)随机选择法求中位数
用随机选择算法randomizedSelect 选择一个基准数,以此进行二分划分,计算出中位数median(x) 和median( y),然后计算n个居民点到邮局的距离总和的最小值。
//--------------------------------------------
//求居民点到邮局的距离和的最小值
//prameter:横坐标数组,纵坐标数组,数组大小
//return:居民点到邮局的距离和的最小值
//--------------------------------------------
int postOffice(int * x, int * y, int size)
{
int minX = randomizedSelect(x, 0, size - 1,(size + 1)/2);
int minY = randomizedSelect(y, 0, size - 1,(size + 1)/2);
int min = getMinSumDistance(x, size, minX) + getMinSumDistance(y, size, minY);
return min;
}
(3)线性时间选择求中位数
用最坏情况下的线性时间选择算法select计算出中位数median(x)和
median( y),然后计算n个居民点到邮局的距离总和的最小值。
//--------------------------------------------
//求居民点到邮局的距离和的最小值
//prameter:横坐标数组,纵坐标数组,数组大小
//return:居民点到邮局的距离和的最小值
//--------------------------------------------
int postOffice(int * x, int * y, int size)
{
int minX = select(x, 0, size - 1,(size + 1)/2);
int minY = select(y, 0, size - 1,(size + 1)/2);
int min = getMinSumDistance(x, size, minX) + getMinSumDistance(y, size, minY);
return min;
}
最坏情况下的线性时间选择算法select:
(1)将n个输入元素划分成n/5的上界 个组,每组5个元素,只可能有一个组不是5个元素。用冒泡排序算法,将每组中的元素排好序,并取出每组的中位数,共n/5的上界 个。
(2)找出这n/5的上界个元素的中位数。如果n/5的上界是偶数,就找它的2个中位数中较大的一个,以这个元素作为划分基准。
2.3算法分析
快速排序选择中位数
快排时间复杂度:O(nlogn),求距离和:O(n)
总复杂度:O(nlogn)。
(2)随机选择法求中位数
最坏情况下,randomizedSelect的时间复杂度是:O(n2),平均时间为O(n)
故时间复杂度为:O(n2)。
线性时间选择求中位数
最坏情况下,select算法时间复杂度为O(n),求距离和:O(n)
总复杂度:O(n)。
以上三种算法的空间复杂度均为O(n)。
其他说明:
本算法 设计说明部分 部分内容(公式)来自互联网
//============================================= //postOfficeQuickSort.cpp //邮局选址问题,由input_assign01_XX.dat输入数据,将结果打印并输出至output.txt //快速排序选择中位数 //by leo //3.17.2011 //============================================= #include<iostream> #include<algorithm> #include<fstream> #include<string> using namespace std; //--------------------------------------------- const int MAX_SIZE = 10000; //居民点最大数目 int x[MAX_SIZE],y[MAX_SIZE]; //居民点横纵坐标 int numResident; //居民点数目 const string outFileName = "output.txt"; //输出文件名称 //--------------------------------------------- //根据用户输入,读取相应文件内容并将之保存到数组中 //--------------------------------------------- void input() { string str; cout << "Please input the input file name(input_assign01_00.dat~input_assign01_10.dat):/n"; cin >> str; ifstream fin(str.c_str()); // ifstream fin("post9.txt"); fin >> numResident; //将输入文件流中的数据读入数组中 for(int i = 0; i < numResident, fin >> x[i] >> y[i]; i++); } //--------------------------------------------- //将minDistance打印并输出至输出文件中 //--------------------------------------------- void output(int minDistance) { ofstream fout(outFileName.c_str()); fout << minDistance <<endl;//输出至文件output.txt cout << minDistance <<endl; } //--------------------------------------------- //快速排序比较函数 //--------------------------------------------- int compare(const void * elem1,const void * elem2) { return *((int *)elem1) - *((int *)elem2); } //-------------------------------------------- //计算居民点横(纵)坐标到邮局横(纵)坐标的距离总和的最小值 //prameter:居民点横(纵)坐标数组,数组大小 //return:数组各元素与中间点差值的绝对值的和 //-------------------------------------------- int getMinSumDistance(int coordinate[], int size) { int sum = 0,mid; mid = coordinate[size / 2]; for(int i = 0; i < size; i++) sum += abs(coordinate[i] - mid); return sum; } //-------------------------------------------- //求居民点到邮局的距离和的最小值 //prameter:横坐标数组,纵坐标数组,数组大小 //return:居民点到邮局的距离和的最小值 //-------------------------------------------- int postOffice(int * x, int * y, int size) { qsort(x,size,sizeof(int),compare); //快排数组x qsort(y,size,sizeof(int),compare); int min = getMinSumDistance(x,size) + getMinSumDistance(y,size); //居民点到邮局的距离和的最小值 return min; } //-------------------------------------------- int main() { input(); output( postOffice(x,y,numResident) ); return 0; } //=============================================
//============================================= //postOfficeRandomSelect.cpp //邮局选址问题,由input_assign01_XX.dat输入数据,将结果打印并输出至output.txt //随机选择法确定中位数 //by leo //3.18.2011 //============================================= #include<iostream> #include<algorithm> #include<fstream> #include<string> #include<time.h> using namespace std; //--------------------------------------------- const int MAX_SIZE = 10000; //居民点最大数目 int x[MAX_SIZE],y[MAX_SIZE]; //居民点横纵坐标 int numResident; //居民点数目 const string outFileName = "output.txt"; //输出文件名称 //--------------------------------------------- //根据用户输入,读取相应文件内容并将之保存到数组中 //--------------------------------------------- void input() { string str; cout << "Please input the input file name(input_assign01_00.dat~input_assign01_10.dat):/n"; cin >> str; ifstream fin(str.c_str()); // ifstream fin("post9.txt"); fin >> numResident; //将输入文件流中的数据读入数组中 for(int i = 0; i < numResident, fin >> x[i] >> y[i]; i++); } //--------------------------------------------- //将minDistance打印并输出至输出文件中 //--------------------------------------------- void output(int minDistance) { ofstream fout(outFileName.c_str()); fout << minDistance <<endl;//输出至文件output.txt cout << minDistance <<endl; } //-------------------------------------------- //产生start与end之间的随机数 //-------------------------------------------- int getRandom(int start, int end) { srand((unsigned)time(NULL)); //产生随机种子 int randSerial = start + (int)(rand()%100/100.0 * (end - start)); return randSerial; } //-------------------------------------------- //以数组中的一个随机数为基准,将coordinate数组二分,前小后大 //return:基准数的下标 //-------------------------------------------- int randomizedPartion(int coordinate[], int start, int end) { int randSerial = getRandom(start, end); //获取随机数 int pivot = coordinate[randSerial]; //产生基准数 int i = start - 1; int j = end + 1; while(1) //以基准数为基准将数组二分 { while (coordinate[++i] < pivot && i <= end); while (coordinate[--j] > pivot); if (i >= j) break; swap(coordinate[i], coordinate[j]); } return j; //返回基准数的下标 } //-------------------------------------------- //求数组中第serial小的元素 //parameter:数组,起始下标,终止下标,待求第serial小的元素下标 //return:数组第serial小的元素 //-------------------------------------------- int randomizedSelect(int coordinate[],int start, int end, int serial) { if(start == end) return coordinate[start + serial - 1]; int bound = randomizedPartion(coordinate,start,end); //将coordinate数组二分,前小后大,返回随机数的下标 int numFront = bound - start + 1; //计算以bound分界的前半区的个数 if(serial <= numFront) return randomizedSelect(coordinate,start,bound,serial); else return randomizedSelect(coordinate,bound + 1,end,serial - numFront); } //-------------------------------------------- //计算数组coordinate中各数到mid的距离和 //return:距离和 //-------------------------------------------- int getMinSumDistance(int coordinate[], int size, int mid) { int sum = 0; for(int i = 0; i < size; i++) sum += abs(coordinate[i] - mid); return sum; } //-------------------------------------------- //求居民点到邮局的距离和的最小值 //prameter:横坐标数组,纵坐标数组,数组大小 //return:居民点到邮局的距离和的最小值 //-------------------------------------------- int postOffice(int * x, int * y, int size) { int minX = randomizedSelect(x, 0, size - 1,(size + 1)/2); int minY = randomizedSelect(y, 0, size - 1,(size + 1)/2); int min = getMinSumDistance(x, size, minX) + getMinSumDistance(y, size, minY); return min; } //-------------------------------------------- int main() { input(); output( postOffice(x,y,numResident) ); return 0; } //=============================================
//============================================= //postOfficeTimeLinearSelect.cpp //邮局选址问题,由input_assign01_XX.dat输入数据,将结果打印并输出至output.txt //线性时间选择确定中位数 //by leo //3.17.2011 //============================================= #include<iostream> #include<algorithm> #include<fstream> #include<string> using namespace std; //--------------------------------------------- const int MAX_SIZE = 10000; //居民点最大数目 int x[MAX_SIZE],y[MAX_SIZE]; //居民点横纵坐标 int numResident; //居民点数目 const string outFileName = "output.txt"; //输出文件名称 //--------------------------------------------- //根据用户输入,读取相应文件内容并将之保存到数组中 //--------------------------------------------- void input() { string str; cout << "Please input the input file name(input_assign01_00.dat~input_assign01_10.dat):/n"; cin >> str; ifstream fin(str.c_str()); // ifstream fin("post9.txt"); fin >> numResident; //将输入文件流中的数据读入数组中 for(int i = 0; i < numResident, fin >> x[i] >> y[i]; i++); } //--------------------------------------------- //将minDistance打印并输出至输出文件中 //--------------------------------------------- void output(int minDistance) { ofstream fout(outFileName.c_str()); fout << minDistance <<endl;//输出至文件output.txt cout << minDistance <<endl; } //-------------------------------------------- //以值pivot为基准将数组arr中arr[left]到arr[right]为两部分 //return:基准的下标 //-------------------------------------------- int partition(int arr[], int left, int right, int pivot) { int i = left - 1; int j = right + 1; while (true) { while (arr[++i] < pivot && i <= right); while (arr[--j] > pivot); if (i >= j) break; swap(arr[i], arr[j]); } return j; } //-------------------------------------------- //将对arr[left]至arr[right]之间的数进行冒泡排序 //return:排序后的数组 //-------------------------------------------- int bubbleSort(int * arr, int left, int right) { for (int i = left; i < left + right; i++) { for(int j = i + 1; j <= right; j++) { if (*(arr + i) > *(arr + j)) swap(*(arr + i),*(arr + j));//temp = *(arr + i),*(arr + i) = *(arr + j), //*(arr + j) = temp; } } return *arr; } //-------------------------------------------- //将数组arr分组排序,并将中位数交换到arr的前面 //-------------------------------------------- void groupSort(int * arr,int left, int right) { //(right-left+1)/5为五元组的个数,即n/5的下界 for (int i = 0; i< (right - left + 1)/5; i++) { int pLeft = left + 5 * i; int pRight = pLeft + 4; bubbleSort(arr,pLeft,pRight); //五元小组内排序 swap(arr[left + i],arr[pLeft + 2]); //将arr[left+5*i]至arr[left+5*i+4]的 //第3小元素与arr[left+i]交换位置; } } //-------------------------------------------- //选择数组arr中arr[left]到arr[right]中第serial小的元素,线性时间选择算法 //return:数组arr中arr[left]到arr[right]中第serial小的元素值 //-------------------------------------------- int select(int * arr,int left, int right, int serial) { if (right - left < 5) { bubbleSort(arr, left, right); //用冒泡排序算法对数组arr[left:right]排序 return arr[left + serial - 1]; } groupSort(arr,left,right); //将数组arr分组排序,并将中位数交换到arr的前面 int pivot = select(arr, left, left + (right - left + 1)/5 - 1, (right - left + 6)/10); //找中位数的中位数,(right-left+1)/5为五元组的个数 //(right-left+6)/10为中位数的中位数为第几小 int bound = partition(arr, left, right, pivot); //以pviot为基准二分arr int numFront = bound - left + 1; //计算以bound分界的前半区的个数 if (serial <= numFront) return select(arr, left, bound, serial); else return select(arr, bound + 1, right, serial-numFront); } //-------------------------------------------- //计算数组coordinate中各数到mid的距离和 //return:距离和 //-------------------------------------------- int getMinSumDistance(int coordinate[], int size, int mid) { int sum = 0; for(int i = 0; i < size; i++) sum += abs(coordinate[i] - mid); return sum; } //-------------------------------------------- //求居民点到邮局的距离和的最小值 //prameter:横坐标数组,纵坐标数组,数组大小 //return:居民点到邮局的距离和的最小值 //-------------------------------------------- int postOffice(int * x, int * y, int size) { int minX = select(x, 0, size - 1,(size + 1)/2); int minY = select(y, 0, size - 1,(size + 1)/2); int min = getMinSumDistance(x, size, minX) + getMinSumDistance(y, size, minY); return min; } //-------------------------------------------- int main() { input(); output( postOffice(x,y,numResident) ); return 0; } //=============================================
相关文章推荐
- 贪心算法--邮局选址,输油管道问题
- 邮局选址问题 (第七题)
- 【动态规划】邮局选址问题
- 邮局选址问题
- 二维带权邮局位置(选址)问题(分别求横坐标、纵坐标的带权中位数)C++实现
- 南邮 OJ 1208 邮局选址问题
- shu_1241 邮局选址问题
- 输油管道问题和邮局选址问题
- 邮局选址问题
- HZNUOJ 1804 邮局选址问题
- 动态规划--邮局选址问题
- 邮局选址问题
- 邮局选址问题(二)
- 邮局选址问题
- 二维邮局选址问题-带权中位数
- 其他题目---邮局选址问题
- 二维带权邮局位置(选址)问题(分别求横坐标、纵坐标的带权中位数)C++实现
- 邮局选址问题
- [递归与分治算法][BOJ]1032-邮局选址问题
- 动态规划--邮局选址问题