shortestdlg.cpp

来自「40多版经典教材《数据结构》(严蔚敏、吴伟民著)全部代码实现。目录下TC是标准C」· C++ 代码 · 共 398 行

CPP
398
字号
// shortestDlg.cpp : implementation file
//

#include "stdafx.h"
#include "shortest.h"
#include "shortestDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CShortestDlg dialog

CShortestDlg::CShortestDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CShortestDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CShortestDlg)
	m_Info = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CShortestDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CShortestDlg)
	DDX_Text(pDX, IDC_INFO, m_Info);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CShortestDlg, CDialog)
	//{{AFX_MSG_MAP(CShortestDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_LBUTTONDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CShortestDlg message handlers

BOOL CShortestDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

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

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

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	int i;
	CreateFUDN(g); // 通过文件构造无向网g
    for(i=0;i<g.vexnum;i++)
      g.arcs[i][i]=0; // ShortestPath_FLOYD()要求对角元素值为0,因为两点相同,其距离为0
    ShortestPath_FLOYD(g,p,d); // 求每对顶点间的最短路径	
	r=14;
	count=0;
	for(i=0;i<2;i++)
	  number[i]=0;
    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CShortestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

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

void CShortestDlg::OnPaint() 
{
	int i,j,q;
	CPaintDC dc(this); // device context for painting
	if (IsIconic())
	{
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

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

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
	    CRect rcClient;
		GetClientRect(&rcClient);
		CFont /*fnBig,*/fnBig2;
		dc.SetTextAlign(TA_CENTER);
		fnBig2.CreatePointFont(120,"宋体",&dc);
		dc.SetBkMode(TRANSPARENT); // 设置文本的背景为透明
		CFont *pFont2=dc.SelectObject(&fnBig2);
		dc.TextOut(280,10,"全国铁路交通示意图");
		CFont fnBig;
		fnBig.CreatePointFont(90,"宋体",&dc);
		CFont *pFont=dc.SelectObject(&fnBig);
		dc.SelectStockObject(NULL_BRUSH); // 设置图形填充为透明
		for(i=0;i<g.vexnum;i++)
		{
			dc.Ellipse(g.vexs[i].x-r,g.vexs[i].y-r,g.vexs[i].x+r,g.vexs[i].y+r);
			if(i>2)
				dc.TextOut(g.vexs[i].x,g.vexs[i].y-r/2,g.vexs[i].a);
		}
		dc.TextOut(70,20,g.vexs[0].a); // 第4个参数是文本长度
		dc.TextOut(278,60,g.vexs[1].a);
		dc.TextOut(574,20,g.vexs[2].a);
		CString m;
		for(i=0;i<g.vexnum;i++)
		{
			for(j=0;j<i;j++)
				if(g.arcs[i][j]!=INFINITY)
				{
			m.Format("%d",g.arcs[i][j]);
			X=g.vexs[j].x-g.vexs[i].x;
			Y=g.vexs[j].y-g.vexs[i].y;
			R=sqrt(X*X+Y*Y);
		    q=int(atan(-Y/X)*1800/3.14159216);
 		    x=int(r*X/R);
			y=int(r*Y/R);
			dc.MoveTo(g.vexs[i].x+x,g.vexs[i].y+y);
			dc.LineTo(g.vexs[j].x-x,g.vexs[j].y-y);
			CFont fnBig1;
			fnBig1.CreateFont(r,0,q,q,int(q*2),
			FALSE,FALSE,FALSE,ANSI_CHARSET,
			OUT_DEFAULT_PRECIS,
			CLIP_DEFAULT_PRECIS,PROOF_QUALITY,
			DEFAULT_PITCH+FF_DONTCARE,"宋体");
			CFont *pFont1=dc.SelectObject(&fnBig1);
            dc.TextOut(g.vexs[j].x-int(X/2),g.vexs[j].y-int(Y/2)+2,m);
				}
		}
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CShortestDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

int CShortestDlg::LocateVex(MGraph G, VertexType u)
 { // 初始条件: 图G存在,u和G中顶点有相同特征
   // 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
   int i;
   for(i=0;i<G.vexnum;++i)
     if(strcmp(u,G.vexs[i].a)==0)
       return i;
   return -1;
 }

void CShortestDlg::CreateFUDN(MGraph &G)
 { // 采用数组(邻接矩阵)表示法,由文件构造没有相关信息的无向网G
   int i,j,k,w;
   VertexType va,vb;
   FILE *graphlist;
   graphlist=fopen("mapvc.txt","r"); // 打开数据文件,并以graphlist表示
   fscanf(graphlist,"%d",&G.vexnum);
   fscanf(graphlist,"%d",&G.arcnum);
   for(i=0;i<G.vexnum;++i) // 构造顶点向量
     fscanf(graphlist,"%s%d%d",G.vexs[i].a,&G.vexs[i].x,&G.vexs[i].y);
   for(i=0;i<G.vexnum;++i) // 初始化邻接矩阵
     for(j=0;j<G.vexnum;++j)
       G.arcs[i][j]=INFINITY; // 网
   for(k=0;k<G.arcnum;++k)
   {
     fscanf(graphlist,"%s%s%d",va,vb,&w);
     i=LocateVex(G,va);
     j=LocateVex(G,vb);
     G.arcs[i][j]=G.arcs[j][i]=w; // 无向网
   }
   fclose(graphlist); // 关闭数据文件
 }


void CShortestDlg::ShortestPath_FLOYD(MGraph G, PathMatrix P, DistancMatrix D)
 { // 用Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]及其带权长度D[v][w]。
   // 若P[v][w][u]为TRUE,则u是从v到w当前求得最短路径上的顶点。算法7.16
   int u,v,w,i;
   for(v=0;v<G.vexnum;v++) // 各对结点之间初始已知路径及距离
     for(w=0;w<G.vexnum;w++)
     {
       D[v][w]=G.arcs[v][w]; // 顶点v到顶点w的直接距离
       for(u=0;u<G.vexnum;u++)
	 P[v][w][u]=FALSE; // 路径矩阵初值
       if(D[v][w]<INFINITY) // 从v到w有直接路径
	 P[v][w][v]=P[v][w][w]=TRUE; // 由v到w的路径经过v和w两点
     }
   for(u=0;u<G.vexnum;u++)
     for(v=0;v<G.vexnum;v++)
       for(w=0;w<G.vexnum;w++)
	 if(D[v][u]<INFINITY&&D[u][w]<INFINITY&&D[v][u]+D[u][w]<D[v][w])
	 { // 从v经u到w的一条路径更短
	   D[v][w]=D[v][u]+D[u][w]; // 更新最短距离
	   for(i=0;i<G.vexnum;i++)
	     P[v][w][i]=P[v][u][i]||P[u][w][i]; // 从v到w的路径经过从v到u和从u到w的所有路径
	 }
 }

void CShortestDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
  // TODO: Add your message handler code here and/or call default

  CString strMessage,ss;
  CDC* pDC=GetDC();  
  pDC->SelectStockObject(NULL_BRUSH); // 设置图形填充为透明
  CPen pendot(PS_DOT,1,RGB(0,0,0)); // 黑色虚线
  CPen penblack(PS_SOLID,1,RGB(0,0,0)); // 黑色实线
  CPen *pOldPen;
  int i,k;
  count++;
  if(count%2) // 鼠标左键单击奇数次
  {
    if(count>1) // 不是第一次求最短距离,要用黑笔重画
	{
	  pOldPen=pDC->SelectObject(&penblack); // 先用黑笔重画 
      pDC->Ellipse(g.vexs[number[0]].x-r,g.vexs[number[0]].y-r,g.vexs[number[0]].x+r,g.vexs[number[0]].y+r); // 起点
      pDC->Ellipse(g.vexs[number[1]].x-r,g.vexs[number[1]].y-r,g.vexs[number[1]].x+r,g.vexs[number[1]].y+r); // 终点
      k=1;
	  while(pa[k]!=-1)
	  {
	    X=double(g.vexs[pa[k]].x-g.vexs[pa[k-1]].x);
	    Y=double(g.vexs[pa[k]].y-g.vexs[pa[k-1]].y);
	    R=sqrt(X*X+Y*Y);
 	    x=int(r*X/R);
	    y=int(r*Y/R);
	    pDC->MoveTo(g.vexs[pa[k-1]].x+x,g.vexs[pa[k-1]].y+y);
	    pDC->LineTo(g.vexs[pa[k]].x-x,g.vexs[pa[k]].y-y);
	    pDC->Ellipse(g.vexs[pa[k]].x-r,g.vexs[pa[k]].y-r,g.vexs[pa[k]].x+r,g.vexs[pa[k]].y+r);
		k++;
	  };
	}
	pOldPen=pDC->SelectObject(&pendot); // 用虚线画 
    for(i=0;i<g.vexnum;i++)
	{
	  X=double(point.x-g.vexs[i].x);
	  Y=double(point.y-g.vexs[i].y);
	  if(int(sqrt(X*X+Y*Y))<=r)
	  {
        pDC->Ellipse(g.vexs[i].x-r,g.vexs[i].y-r,g.vexs[i].x+r,g.vexs[i].y+r); // 用红笔重画鼠标所点之顶点
	    number[0]=i; // 记下该顶点之编号
		break;
	  }
	}
	m_Info=""; // 静态文本框为空
	UpdateData(FALSE);
  }
  else// 鼠标左键单击偶数次
  {
    pOldPen=pDC->SelectObject(&pendot); // 用虚线画 
    for(i=0;i<g.vexnum;i++)
	{
	  X=point.x-g.vexs[i].x;
	  Y=point.y-g.vexs[i].y;
	  if(sqrt(X*X+Y*Y)<=r)
	  {
        pDC->Ellipse(g.vexs[i].x-r,g.vexs[i].y-r,g.vexs[i].x+r,g.vexs[i].y+r); // 用红笔重画鼠标所点之顶点
	    number[1]=i; // 记下该顶点之编号
		break;
	  }
	}
	if(d[number[0]][number[1]]<INFINITY) // 有通路
	{
	  path1(g,p,number[0],number[1],pa); // 求最短路径上由起点城市到终点城市沿途所经过的城市
	  strMessage.Format("%s到%s的最短距离为%d\n途经: %s ",g.vexs[number[0]].a,g.vexs[number[1]].a,d[number[0]][number[1]],g.vexs[pa[0]].a);
	  int k=1;
	  while(pa[k]!=-1)
	  {
		X=g.vexs[pa[k]].x-g.vexs[pa[k-1]].x;
		Y=g.vexs[pa[k]].y-g.vexs[pa[k-1]].y;
		R=sqrt(X*X+Y*Y);
 		x=int(r*X/R);
		y=int(r*Y/R);
		pDC->MoveTo(g.vexs[pa[k-1]].x+x,g.vexs[pa[k-1]].y+y);
		pDC->LineTo(g.vexs[pa[k]].x-x,g.vexs[pa[k]].y-y);
		pDC->Ellipse(g.vexs[pa[k]].x-r,g.vexs[pa[k]].y-r,g.vexs[pa[k]].x+r,g.vexs[pa[k]].y+r);
		ss.Format("%s ",g.vexs[pa[k++]].a);
		strMessage+=ss;
	  };
	}
    else
	{
	  strMessage.Format("%s到%s没有路径可通\n",g.vexs[number[0]].a,g.vexs[number[1]].a);
	  pa[1]=-1; // 不画线的标志
	}
	m_Info=strMessage;
	UpdateData(FALSE);
  }
  CDialog::OnLButtonDown(nFlags, point);
}

void CShortestDlg::path1(MGraph G, PathMatrix P, int i, int j, int pa[])
{ // 求由序号为i的起点城市到序号为j的终点城市最短路径沿途所经过的城市
  int k,l;
  int m=i; // 起点城市序号赋给m
  l=0;
  for(k=0;k<G.vexnum;k++)
    pa[k]=-1; // pa的初值
  while(m!=j) // 没到终点城市
  {
    G.arcs[m][m]=INFINITY; // 对角元素赋值无穷大
    for(k=0;k<G.vexnum;k++)
      if(G.arcs[m][k]<INFINITY&&P[m][j][k]) // m到k有直接通路,且k在m到j的最短路径上
      {
	    pa[l++]=m;
		G.arcs[m][k]=G.arcs[k][m]=INFINITY; // 将直接通路设为不通
		m=k; // 经过的城市序号赋给m,继续查找
		break;
      }
  }
  pa[l]=j; // 终点城市
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?