| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2601 人关注过本帖
标题:经典分治问题
只看楼主 加入收藏
编程探索者
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2010-7-21
结帖率:100%
收藏
已结贴  问题点数:20 回复次数:20 
经典分治问题
最近点对问题:
输入n个数的坐标,求出最近的一对点的距离,用分治,限时1s
加点注释哦
搜索更多相关主题的帖子: 经典 分治 
2010-08-02 19:59
LSYHEFENG
Rank: 2
等 级:论坛游民
帖 子:112
专家分:71
注 册:2010-7-17
收藏
得分:5 
分治太难,给你个暴力破解法(显然会超时),分治只能请教真正的C语言高手了
#include <stdio.h>
#include <math.h>

int main()
{   
  
    float distanc_y(float x1,float y1,float x2,float y2);
    int i,j,k;
    long N;
    float x[100002],y[100002],min,cimin;

    while(scanf("%ld",&N)!=EOF)
    {  
       if(N==0)
       break;
       min=99999999;
       for(i=0;i<N;i++)
       scanf("%f%f",&x[i],&y[i]);
      
         for(i=0;i<N-1;i++)
       {
           k=i;
            for(j=k+1;j<N;j++)
            {
                cimin=distanc_y(x[k],y[k],x[j],y[j]);
                if(min>cimin)
                    min=cimin;
            }
       }
       printf("%.2f\n",min);

    }
   
    return 0;
}


float distanc_y(float x1,float y1,float x2,float y2)
{
    float z;
    z=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    return z;
}
2010-08-02 20:14
编程探索者
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2010-7-21
收藏
得分:0 
不管怎样,谢谢楼上的关注,让我们一起等待真正的高手出现吧
2010-08-02 20:24
uppermore
Rank: 2
等 级:论坛游民
帖 子:33
专家分:26
注 册:2010-7-20
收藏
得分:0 
分治是什么
2010-08-02 21:36
编程探索者
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2010-7-21
收藏
得分:0 
一种算法
2010-08-02 22:00
uppermore
Rank: 2
等 级:论坛游民
帖 子:33
专家分:26
注 册:2010-7-20
收藏
得分:0 
说原理,难道像那种什么折半查找什么的?
2010-08-02 23:57
liveningning
Rank: 1
等 级:新手上路
帖 子:17
专家分:9
注 册:2010-8-2
收藏
得分:0 
算法很多种
自己习惯的就好

www.
聚焦!专业!高效!服务人才!成就客户
2010-08-03 09:01
编程探索者
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2010-7-21
收藏
得分:0 
高手们来看看啦
2010-08-03 10:27
sunyh1999
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:14
帖 子:1178
专家分:3032
注 册:2009-5-17
收藏
得分:6 
C++做分治法的过程:
程序代码:
#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;
}

 

欢迎来到我的博客:http://blog..cn/noisunyuhong
2010-08-03 12:02
linjx0123
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:14
帖 子:279
专家分:1362
注 册:2006-4-7
收藏
得分:6 
这个题目我写过,用java写的
程序代码:
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;
为中心分为左边和右边,然后最短点对就是左边的最短点对距离lm、右边的最短点对距离rm,
以及左边和右边的最短点对距离三个距离的最小值就是最短点对距离。
左边的最短点对距离lm、右边的最短点对距离rm用递归可得,难点在于求左边和右边的最短点对距离。当然不能所有点进行比较,那样肯定超时。
所以,设min=lm,rm的最小值,那么左边到右边的最短点必须满足左边到中心轴的距离<=min,右边到中心轴的距离<=min.将满足条件的点对放进p中。
然后再对P进行y轴排序。最后对排序好的点对求解。
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]));
    }

其中 y[p[j]] - y[p[i]] < min这个是:两个点的y轴距离要小于min,这样假如符合条件的y轴有400或者更多个点,就可以排序掉很多。

虽然是用java写的,但是基本还是跟c语言差不多的,仅供大家参考
2010-08-03 14:11
快速回复:经典分治问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.023531 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved