经典分治问题
最近点对问题:输入n个数的坐标,求出最近的一对点的距离,用分治,限时1s
加点注释哦
#include<iostream> #include<cmath> using namespace std; // ------------------------------------ typedef struct Node{ int x; int y; }Node; typedef struct NList{ Node* data; int count; }NList; typedef struct CloseNode{ Node a; Node b; double space; }CloseNode; int max; //=============================================== //归并排序 void Merge(Node SR[],Node TR[],int i,int m,int n){ //将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n] int j,k; for(j=m+1,k=i;i<=m&&j<=n;++k) if(SR[i].x<=SR[j].x) TR[k]=SR[i++]; else TR[k]=SR[j++]; while(i<=m) TR[k++]=SR[i++]; while(j<=n) TR[k++]=SR[j++]; } void Msort(Node SR[],Node TR1[],int s,int t){ //将SR[s..t]归并排序为TR1[s..t] if(s==t) TR1[s]=SR[s]; else{ int m = (s+t)/2; Node *TR2=new Node[max];//new Node[t-s+1];//这个空间挂挂的,从s到t,这里是从0到t-s Msort(SR,TR2,s,m); Msort(SR,TR2,m+1,t); Merge(TR2,TR1,s,m,t); } } void MergeSort(NList L){ Msort(L.data,L.data,0,L.count-1); } // ================================================== // ------------------------------------------------ //输入各点 到数据结构NList中 void create(NList & L){ cout<<"请输入平面上点的数目:\n"; cin>>max; L.count=max; L.data = new Node[L.count];//====================动态空间分配!!!!注意 cout<<"输入"<<L.count<<"个点坐标 X,Y,请不要输入过大,超过计算机计算范围,本程序使用int型(@+@):"<<endl; for(int i=0;i<L.count;++i) cin>>L.data[i].x>>L.data[i].y; } // -------------------------------------------------- //求距离平方的函数 double Distinguish2(Node a,Node b){ return ((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y)); } // -------------------------------------------------- //蛮力法求最近对 void BruteForce(const NList & L,CloseNode & cnode,int begin,int end){ for(int i=begin;i<=end;++i) for(int j=i+1;j<=end;++j){ double space = Distinguish2(L.data[i],L.data[j]); if(space<cnode.space){ cnode.a=L.data[i]; cnode.b=L.data[j]; cnode.space=space; } } } // ===================================================== //分治法求最近对 中间2d对称区的算法 void Middle(const NList & L,CloseNode & cnode,int mid,int midX){ int i,j; int d = sqrt(cnode.space); i=mid; while(i>=0&&L.data[i].x>=(midX-d)){ j=mid; while(L.data[++j].x<=(midX+d)&&j<=L.count){//1,j++ 2<=,>= if(L.data[j].y<(L.data[i].y-d)||L.data[j].y>(L.data[i].y+d)) continue; double space = Distinguish2(L.data[i],L.data[j]); if(cnode.space>space){ cnode.a=L.data[i]; cnode.b=L.data[j]; cnode.space=space; } } --i; } } // ---------------------------------------------- //分治法求最近对 void DivideAndConquer(const NList &L,CloseNode & closenode,int begin,int end){ if((end-begin+1)<4) BruteForce(L,closenode,begin,end); else{ int mid = (begin+end)/2; int midX = L.data[mid].x; DivideAndConquer(L,closenode,begin,mid); DivideAndConquer(L,closenode,mid+1,end); Middle(L,closenode,mid,midX); } } //================================================== // ------------------------------------------------ int main(){ NList list; CloseNode closenode; closenode.space = 10000; create(list); cout<<"各点坐标为:"<<endl; for(int i=0;i<list.count;++i) cout<<"X="<<list.data[i].x<<" Y="<<list.data[i].y<<"\n"; BruteForce(list,closenode,0,list.count-1); cout<<"用蛮力法求最近对:"<<endl; cout<<"最近对为点 ("<<closenode.a.x<<","<<closenode.a.y<<")和点("<<closenode.b.x<<","<<closenode.b.y<<")\n"<<"最近距离为: "<<closenode.space<<endl; cout<<"===================================================================="<<endl; cout<<"===================================================================="<<endl; cout<<"用分治法求最近对:"<<endl; MergeSort(list); cout<<"经过归并排序后的各点:"<<endl; for(int j=0;j<list.count;++j) cout<<"X="<<list.data[j].x<<" Y="<<list.data[j].y<<"\n"; DivideAndConquer(list,closenode,0,list.count-1); cout<<"最近对为点 ("<<closenode.a.x<<","<<closenode.a.y<<")和点("<<closenode.b.x<<","<<closenode.b.y<<")\n"<<"最近距离为: "<<closenode.space<<endl; return 0; }
import java.util.Scanner; public class Main { static double x[]; static double y[]; static int p[]; private static double distance(int i, int j) { return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]); } private static void swap(int i, int j) { double temp = x[i]; x[i] = x[j]; x[j] = temp; temp = y[i]; y[i] = y[j]; y[j] = temp; } private static void qsortX(int l, int r) { int i = l, j = r; double mid = x[(l + r) / 2]; do { while (x[i] < mid) i++; while (x[j] > mid) j--; if (i <= j) { swap(i, j); i++; j--; } } while (i <= j); if (i < r) qsortX(i, r); if (l < j) qsortX(l, j); } private static void qsortY(int l, int r) { int i = l, j = r; double mid = y[p[(l + r) / 2]]; do { while (y[p[i]] < mid) i++; while (y[p[j]] > mid) j--; if (i <= j) { int temp = p[i]; p[i] = p[j]; p[j] = temp; i++; j--; } } while (i <= j); if (i < r) qsortY(i, r); if (l < j) qsortY(l, j); } private static double getMin(double a, double b) { return a < b ? a : b; } private static double findMin(int l, int r) { if (l == r) return 999999999; if (l + 1 == r) { return distance(l, r); } int d = (l + r) / 2; double lm = findMin(l, d), rm = findMin(d + 1, r), mid = (x[l] + x[r]) / 2, min; min = getMin(lm, rm); int tot = 0; for (int i = l; i <= r; i++) { double k = x[i] - mid; if (4 * k * k < min) p[++tot] = i; } qsortY(1, tot); for (int i = 1; i < tot; i++) for (int j = i + 1; j <= tot && y[p[j]] - y[p[i]] < min; j++) { min = getMin(min, distance(p[i], p[j])); } return min; } public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); double min = 0; while (true) { if (n == 0) break; x = new double[n + 1]; y = new double[n + 1]; p = new int[n + 1]; for (int i = 1; i <= n; i++) { x[i] = in.nextDouble(); y[i] = in.nextDouble(); } qsortX(1, n); min = findMin(1, n); System.out.printf("%.2f", Math.sqrt(min) / 2); System.out.println(); n = in.nextInt(); } } }基本思想是,先对x轴进行排序,再将所有点集以int d = (l + r) / 2;