找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 2708|回复: 1

二维空间的最近点对问题图解(动态规划算法实现)

[复制链接]
发表于 2014-7-29 13:11:08 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
在网上搜了一遍,貌似没找到这种实际代码,于是自己用MFC写了一下,当然这种问题适合用图形方式来直观展示,整个搜索过程一目了然
采用的算法是动态规划,应用算法之前需要对所有点先按照横坐标排下序,这样有利于区域判定

效果展示:
红色代表已找到的最近点,蓝色表示正在找的点
QQ图片20140729131005.jpg

核心代码:
  1. // FindNearestPointDlg.cpp : implementation file
  2. //

  3. #include "stdafx.h"
  4. #include "FindNearestPoint.h"
  5. #include "FindNearestPointDlg.h"

  6. #include <math.h>
  7. #include <vector>
  8. #include <queue>
  9. #include <stdlib.h>
  10. #include <time.h>

  11. using namespace std;

  12. #define distance(a,b) sqrt(((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)))
  13. #define abs(a,b) ((a>b)?a-b:b-a)

  14. #ifdef _DEBUG
  15. #define new DEBUG_NEW
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CFindNearestPointDlg dialog

  21. int showdata::curminindex1=INT_MAX;
  22. int showdata::curminindex2=INT_MAX;
  23. float showdata::mindis=INT_MAX;

  24. CFindNearestPointDlg::CFindNearestPointDlg(CWnd* pParent /*=NULL*/)
  25.         : CDialog(CFindNearestPointDlg::IDD, pParent)
  26. {
  27.         //{{AFX_DATA_INIT(CFindNearestPointDlg)
  28.         //}}AFX_DATA_INIT
  29.         // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  30.         m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  31. }

  32. void CFindNearestPointDlg::DoDataExchange(CDataExchange* pDX)
  33. {
  34.         CDialog::DoDataExchange(pDX);
  35.         //{{AFX_DATA_MAP(CFindNearestPointDlg)
  36.         DDX_Control(pDX, IDC_VELOCITY, m_velocity);
  37.         DDX_Control(pDX, IDC_PTNUM, m_ptnum);
  38.         DDX_Control(pDX, IDC_DRAW, m_draw);
  39.         //}}AFX_DATA_MAP
  40. }

  41. BEGIN_MESSAGE_MAP(CFindNearestPointDlg, CDialog)
  42.         //{{AFX_MSG_MAP(CFindNearestPointDlg)
  43.         ON_WM_SYSCOMMAND()
  44.         ON_WM_PAINT()
  45.         ON_WM_QUERYDRAGICON()
  46.         ON_BN_CLICKED(IDC_MAKE, OnMake)
  47.         ON_WM_TIMER()
  48.         ON_NOTIFY(NM_CUSTOMDRAW, IDC_VELOCITY, OnCustomdrawVelocity)
  49.         //}}AFX_MSG_MAP
  50. END_MESSAGE_MAP()

  51. /////////////////////////////////////////////////////////////////////////////
  52. // CFindNearestPointDlg message handlers

  53. BOOL CFindNearestPointDlg::OnInitDialog()
  54. {
  55.         CDialog::OnInitDialog();

  56.         // Add "About..." menu item to system menu.

  57.         // IDM_ABOUTBOX must be in the system command range.
  58.         ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  59.         ASSERT(IDM_ABOUTBOX < 0xF000);

  60.         CMenu* pSysMenu = GetSystemMenu(FALSE);
  61.         if (pSysMenu != NULL)
  62.         {
  63.                 CString strAboutMenu;
  64.                 strAboutMenu.LoadString(IDS_ABOUTBOX);
  65.                 if (!strAboutMenu.IsEmpty())
  66.                 {
  67.                         pSysMenu->AppendMenu(MF_SEPARATOR);
  68.                         pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  69.                 }
  70.         }

  71.         // Set the icon for this dialog.  The framework does this automatically
  72.         //  when the application's main window is not a dialog
  73.         SetIcon(m_hIcon, TRUE);                        // Set big icon
  74.         SetIcon(m_hIcon, FALSE);                // Set small icon
  75.        
  76.         // TODO: Add extra initialization here

  77.         srand(time(NULL));
  78.         SetTimer(1,200,NULL);
  79.         m_ptnum.SetRange(10,1000);
  80.         m_ptnum.SetPos(10);
  81.         m_velocity.SetRange(200,1000);
  82.         m_velocity.SetPos(200);

  83.         return TRUE;  // return TRUE  unless you set the focus to a control
  84. }

  85. void CFindNearestPointDlg::OnSysCommand(UINT nID, LPARAM lParam)
  86. {
  87.         CDialog::OnSysCommand(nID, lParam);
  88. }

  89. // If you add a minimize button to your dialog, you will need the code below
  90. //  to draw the icon.  For MFC applications using the document/view model,
  91. //  this is automatically done for you by the framework.

  92. void CFindNearestPointDlg::OnPaint()
  93. {
  94.         if (IsIconic())
  95.         {
  96.                 CPaintDC dc(this); // device context for painting

  97.                 SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

  98.                 // Center icon in client rectangle
  99.                 int cxIcon = GetSystemMetrics(SM_CXICON);
  100.                 int cyIcon = GetSystemMetrics(SM_CYICON);
  101.                 CRect rect;
  102.                 GetClientRect(&rect);
  103.                 int x = (rect.Width() - cxIcon + 1) / 2;
  104.                 int y = (rect.Height() - cyIcon + 1) / 2;

  105.                 // Draw the icon
  106.                 dc.DrawIcon(x, y, m_hIcon);
  107.         }
  108.         else
  109.         {
  110.                 CDialog::OnPaint();

  111.                 if(show.empty())
  112.                         return;

  113.                 showdata& cur=show.front();

  114.                 CClientDC dc(&m_draw);
  115.                 RECT rt;
  116.                 CBrush clearbrush(RGB(255,255,255));
  117.                 CDC MemDC;
  118.                 CBitmap MemBitmap;
  119.                 m_draw.GetClientRect(&rt);
  120.                 MemDC.CreateCompatibleDC(&dc);
  121.                 MemBitmap.CreateCompatibleBitmap(&dc,rt.right,rt.bottom);
  122.                 MemDC.SelectObject(&MemBitmap);
  123.                
  124.                 MemDC.FillRect(&rt,&clearbrush);

  125.        
  126.                 CBrush normalbrush(RGB(0,0,0)),stressbrush(RGB(0,255,0,));
  127.                 CPen normalpen(PS_SOLID,1,RGB(0,0,0)),stresspen(PS_SOLID,2,RGB(0,255,0));
  128.                 MemDC.SelectObject(&normalbrush);

  129.                 for(int i=0;i<cur.points.size();i++)
  130.                 {
  131.                         pt& curpt=cur.points.at(i);
  132.                         MemDC.Ellipse(curpt.x-5,curpt.y-5,curpt.x+5,curpt.y+5);
  133.                 }

  134.                 if(cur.type == 1)
  135.                 {
  136.                         MemDC.SelectObject(&stressbrush);
  137.                         pt& pt1=cur.points.at(cur.data.line.index1);
  138.                         pt& pt2=cur.points.at(cur.data.line.index2);
  139.                         MemDC.Ellipse(pt1.x-5,pt1.y-5,pt1.x+5,pt1.y+5);
  140.                         MemDC.Ellipse(pt2.x-5,pt2.y-5,pt2.x+5,pt2.y+5);
  141.                         MemDC.SelectObject(stresspen);
  142.                         MemDC.MoveTo(pt1.x,pt1.y);
  143.                         MemDC.LineTo(pt2.x,pt2.y);
  144.                 }
  145.                 else if(cur.type == 2)
  146.                 {
  147.                         MemDC.SelectObject(&stressbrush);
  148.                         pt& pt1=cur.points.at(cur.data.rect.leftindex);
  149.                         pt& pt2=cur.points.at(cur.data.rect.rightindex);
  150.                         MemDC.Ellipse(pt1.x-5,pt1.y-5,pt1.x+5,pt1.y+5);
  151.                         MemDC.Ellipse(pt2.x-5,pt2.y-5,pt2.x+5,pt2.y+5);
  152.                         MemDC.SelectObject(stresspen);
  153.                         MemDC.MoveTo(pt1.x,pt1.y);
  154.                         MemDC.LineTo(pt2.x,pt2.y);       
  155.                         MemDC.SelectObject(normalpen);
  156.                         int d=cur.data.rect.d;
  157.                         pt& mid=cur.points.at(cur.data.rect.midindex);
  158.                         MemDC.MoveTo(mid.x,mid.y-d);
  159.                         MemDC.LineTo(mid.x+d,mid.y-d);
  160.                         MemDC.LineTo(mid.x+d,mid.y+d);
  161.                         MemDC.LineTo(mid.x,mid.y+d);
  162.                         MemDC.LineTo(mid.x,mid.y-d);
  163.                 }

  164.                 if(cur.mindis < INT_MAX)//如果有最小距离点
  165.                 {
  166.                         CBrush b(RGB(255,0,0));
  167.                         CPen p(PS_SOLID,2,RGB(255,0,0));
  168.                         pt& pt1=cur.points.at(cur.curminindex1);
  169.                         pt& pt2=cur.points.at(cur.curminindex2);
  170.                         MemDC.SelectObject(b);
  171.                         MemDC.SelectObject(p);
  172.                         MemDC.Ellipse(pt1.x-5,pt1.y-5,pt1.x+5,pt1.y+5);
  173.                         MemDC.Ellipse(pt2.x-5,pt2.y-5,pt2.x+5,pt2.y+5);
  174.                         MemDC.MoveTo(pt1.x,pt1.y);
  175.                         MemDC.LineTo(pt2.x,pt2.y);
  176.                 }

  177.                 if(show.size() > 1)
  178.                         show.pop();

  179.                 dc.BitBlt(0,0,rt.right,rt.bottom,&MemDC,0,0,SRCCOPY);
  180.                 MemDC.DeleteDC();
  181.                 MemBitmap.DeleteObject();
  182.         }
  183. }

  184. // The system calls this to obtain the cursor to display while the user drags
  185. //  the minimized window.
  186. HCURSOR CFindNearestPointDlg::OnQueryDragIcon()
  187. {
  188.         return (HCURSOR) m_hIcon;
  189. }

  190. void CFindNearestPointDlg::OnMake()
  191. {
  192.         // TODO: Add your control notification handler code here
  193.         data.clear();
  194.         while(!show.empty())
  195.                 show.pop();

  196.         showdata::curminindex1=INT_MAX;
  197.         showdata::curminindex2=INT_MAX;
  198.         showdata::mindis=INT_MAX;

  199.         RECT rt;
  200.         m_draw.GetClientRect(&rt);

  201.         int i,j;
  202.         int size=m_ptnum.GetPos();
  203.         TRACE("width:%d height:%d\n",rt.right,rt.bottom);
  204.         for(i=0;i<size;i++)
  205.         {
  206.                 int x=rand()%rt.right,y=rand()%rt.bottom;
  207.                 data.push_back(pt(x,y));
  208.         }

  209.         //先排序
  210.         for(i=0;i < size-1;i++)
  211.         {
  212.                 for(j=size-1;j > i;j--)
  213.                 {
  214.                         if(data[j].x < data[j-1].x)
  215.                         {
  216.                                 int tmpx=data[j].x;
  217.                                 int tmpy=data[j].y;
  218.                                 data[j].x=data[j-1].x;
  219.                                 data[j].y=data[j-1].y;
  220.                                 data[j-1].x=tmpx;
  221.                                 data[j-1].y=tmpy;
  222.                         }
  223.                 }
  224.         }

  225.         for(i=0;i<size;i++)
  226.         {
  227.                 TRACE("%d:(%d,%d)\n",i,data.at(i).x,data.at(i).y);
  228.         }

  229.         show.push(showdata(data));
  230.         FindNear(0,size-1);
  231.         show.push(showdata(data));
  232.         pt& pt1=data.at(showdata::curminindex1);
  233.         pt& pt2=data.at(showdata::curminindex2);
  234.         TRACE("min:(%d,%d)->(%d,%d)=%f\n",pt1.x,pt1.y,pt2.x,pt2.y,showdata::mindis);

  235.         Invalidate(FALSE);
  236. }

  237. void CFindNearestPointDlg::OnTimer(UINT nIDEvent)
  238. {
  239.         // TODO: Add your message handler code here and/or call default
  240.         Invalidate(FALSE);
  241.        
  242.         CDialog::OnTimer(nIDEvent);
  243. }

  244. float CFindNearestPointDlg::FindnearIntersect(float& curmin,int begin,int end)
  245. {
  246.         int mid=(end-begin)/2;
  247.         //找到所有在中位数左侧且横坐标距离中位数横坐标小于curmin的点
  248.         for(int i=mid;i >= begin;i--)
  249.         {
  250.                 if(data[mid].x - data[i].x > curmin)
  251.                         break;
  252.                
  253.                 //对于每一个这样的点寻找右侧可能的6个邻点
  254.                 for(int j=mid+1;j <= end;j++)
  255.                 {
  256.                         if(data[j].x - data[mid].x > curmin)
  257.                                 break;
  258.                         if(abs(data[j].y,data[mid].y) > curmin)
  259.                                 continue;
  260.                        
  261.                         show.push(showdata(i,j,mid,curmin,data,curmin));
  262.                         //对于在2d*d矩形内的点
  263.                         float dis=distance(data[i],data[j]);
  264.                         if(dis < curmin)
  265.                         {
  266.                                 curmin=dis;
  267.                                 show.push(showdata(i,j,data,curmin));
  268.                         }
  269.                 }
  270.         }
  271.         return curmin;
  272. }

  273. float CFindNearestPointDlg::FindNear(int begin,int end)
  274. {
  275.         if(begin == end)//如果只有1个点,则距离设为无穷大
  276.                 return INT_MAX;
  277.         else if(begin+1 == end)//如果有2个点,则返回他们的距离
  278.         {
  279.                 float dis=distance(data[begin],data[end]);
  280.                 show.push(showdata(begin,end,data,dis));
  281.                 return dis;
  282.         }
  283.        
  284.         int mid=(end+begin)/2;
  285.        
  286.         //(begin,end)点的最小距离=min[(begin,mid)点的最小距离,(mid+1,end)点的最小距离,(begin,mid)右侧点和(mid+1,end)左侧点最小距离]
  287.         float d1=FindNear(begin,mid);//(begin,mid)点的最小距离
  288.         float d2=FindNear(mid+1,end);//(mid+1,end)点的最小距离
  289.         float curmin=(d1<d2)?d1:d2;
  290.        
  291.         return FindnearIntersect(curmin,begin,end);//(begin,mid)右侧点和(mid+1,end)左侧点最小距离
  292. }

  293. void CFindNearestPointDlg::OnCustomdrawVelocity(NMHDR* pNMHDR, LRESULT* pResult)
  294. {
  295.         // TODO: Add your control notification handler code here
  296.         KillTimer(1);
  297.         SetTimer(1,m_velocity.GetPos(),NULL);
  298.         *pResult = 0;
  299. }
复制代码
回复

使用道具 举报

 楼主| 发表于 2014-7-29 13:11:36 | 显示全部楼层
可以调整点数和搜索速度
工程:
FindNearestPoint.rar (1 MB, 下载次数: 71)
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-22 16:08 , Processed in 0.034213 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表