zoukankan      html  css  js  c++  java
  • MFC实现红黑砖块

    MFC实现红黑砖块
    ##题目 老题目了,给定w,h长宽的图,上面有颜色不同的瓷砖,黑和红,问从给的起点出发,只能走黑色瓷砖,能走多少块,可视化输出过程 ##思路 咋一看搜索水题,但是要用可视化,要用模板类,,,崩溃掉了,又得拾起MFC了,在学会别的可视化之前,先凑活吧 每个点可以连4条边,超过边界的不连,从起点dfs,遍历每一个相邻的点,判断是不是#黑砖块,是就入栈,vis数组更新为true,每次出栈的时候涂色,难点其实不在图算法,而是MFC画图,,,, ###1)图的模板类设计 只用一个class T就行了,没有边权值,基本上都是书上的代码 ``` #pragma once #include using namespace std; const int DefaultSize = 1000; template struct Edge { int dest; Edge*link; Edge(){} Edge(int to) :dest(to), link(NULL){} }; template struct Vertex { T data; Edge*adj; }; template class Graph{ public: Graph(int sz=DefaultSize); ~Graph(); int GetNodeNum() { return numVertices; } bool insertVertex(const T&vertex); bool insertEdge(int v1, int v2); int getFirstNeighbor(int v); int getNextNeighbor(int v, int w); T getValue(int v); void clear(); protected: Vertex*NodeTable; int numVertices; int maxVertices; int numEdge; }; template Graph::Graph(int sz) { maxVertices = sz; numVertices =numEdge=0; NodeTable = new Vertex[maxVertices]; if (NodeTable == NULL) { cerr << "错误" << endl; exit(1); } for (int i(0); i < maxVertices; i++) { NodeTable[i].adj = NULL; } } template Graph::~Graph() { for (int i(0); i < numVertices; i++) { Edge*p = NodeTable[i].adj; while (p != NULL) { NodeTable[i].adj = p->link; delete p; p = NodeTable[i].adj; } } delete[]NodeTable; } template bool Graph::insertVertex(const T&vertex) { if (numVertices == maxVertices)return false; NodeTable[numVertices].data = vertex; numVertices++; return true; } template bool Graph::insertEdge(int v1, int v2) { if (v1 >= 0 && v1 < numVertices&&v2 >= 0 && v2 < numVertices) { Edge*p = NodeTable[v1].adj; while (p != NULL && p->dest != v2) { p = p->link; } if (p != NULL)return false; p = new Edge; p->dest = v2; p->link = NodeTable[v1].adj; NodeTable[v1].adj = p; numEdge++; } return 0; } template int Graph::getFirstNeighbor(int v) { if (v != -1) { Edge*p = NodeTable[v].adj; if (p != NULL)return p->dest; } return -1; } template int Graph::getNextNeighbor(int v, int w) { if (v != -1) { Edge*p = NodeTable[v].adj; while (p != NULL && p->dest != w) { p = p->link; } if (p != NULL && p->link != NULL) return p->link->dest; } return -1; } template void Graph::clear() { for (int i(0); i < numVertices; i++) { Edge*p = NodeTable[i].adj; while (p != NULL) { NodeTable[i].adj = p->link; delete p; p = NULL; p = NodeTable[i].adj; } } numVertices = 0; numEdge = 0; } template T Graph::getValue(int v) { if (v == -1)return NULL; return NodeTable[v].data; } ```

    2)界面设计

    好了,最简单的模板类设计已经解决了(括弧笑),接下来我们开始做界面。首先建立一个基于单文档的MFC工程,打开资源视图,在工具条那里加3个按钮进去,然后分别在view类里面添加事件处理程序

    3)数据输入

    先定义view下的自定义数据

    	int W, H;
    	int Spos;
    	bool is_OK = false;
    	char feld[30][30];
    	Graph<char>G;
    	afx_msg void OnReadGraph();
    	afx_msg void Onbuild();
    	void DrawRect(CRect crect, int border, CBrush&brush);
    	void DrawCircle(CRect rect, int border, CBrush&brush);
    	afx_msg void Onstart();
    

    数据输入用了自带的资源管理器类,把txt的房间文件读取,需要注意的是,W和H后面都要加空格,这才能从strline中提取单个数字出来

    void C走瓷砖View::OnReadGraph()
    {
    	Invalidate();
    	CString fileName;
    	CFileDialog dlg(TRUE);
    	if (IDOK == dlg.DoModal())
    		fileName = dlg.GetPathName();
    	if (fileName.IsEmpty())
    		return;
    	CStdioFile file;
    	if (file.Open(fileName, CFile::modeRead))
    	{
    		is_OK = true;
    		CString strLine;
    		CString str;
    		file.ReadString(strLine);
    		AfxExtractSubString(str, strLine, 0, ' ');
    		W = _ttoi(str);
    		AfxExtractSubString(str, strLine, 1, ' ');
    		H = _ttoi(str);
    		for (int i(0); i < H; i++) {
    			file.ReadString(strLine);
    			for (int j(0); j < W; j++) {
    				feld[i][j] = strLine[j];
    			}
    		}
    		file.Close();
    	}
    	// TODO: 在此添加命令处理程序代码
    }
    

    4)建图并画图

    先定义两个函数,一个画矩形一个画圆,

    void C走瓷砖View::DrawRect(CRect rect,int border,CBrush&brush)
    {
    	CClientDC dc(this);
    	//dc.SetROP2(R2_XORPEN);
    	
    	CPen pen;
    	pen.CreatePen(PS_SOLID, border, RGB(128,128, 128));
    	CPen *ppen = dc.SelectObject(&pen);
    	dc.Rectangle(rect);
    	dc.SelectObject(ppen);
    	CBrush *pbrush;
    	pbrush = dc.SelectObject(&brush);
    	dc.Rectangle(rect);
    	dc.SelectObject(pbrush);
    	// TODO: 在此处添加实现代码.
    }
    void C走瓷砖View::DrawCircle(CRect rect, int border, CBrush&brush)
    {
    	CClientDC dc(this);
    	int width = 50 / max(W, H);
    	CRect newrect(rect.left + width, rect.top +width, rect.right - width, rect.bottom - width);
    	CBrush *pbrush;
    	pbrush = dc.SelectObject(&brush);
    	dc.Ellipse(newrect);
    	dc.SelectObject(pbrush);
    	// TODO: 在此处添加实现代码.
    }
    

    传3个参数进去,矩形,边界宽度,填充颜色,先填充颜色,再用pen画框子好看点
    接下来是建图的函数

    void C走瓷砖View::Onbuild()
    {
    	if (is_OK == false) {
    		AfxMessageBox(_T("请先读取房间!"));
    		return;
    	}
    	G.clear();
    	int cut=0;
    	for (int i(0); i < H; i++) {
    		for (int j(0); j < W; j++) {
    			if (feld[i][j] == '@') {
    				Spos = i * W + j;
    			}
    			G.insertVertex(feld[i][j]);
    			cut++;
    		}
    	}
    	int s1, s2, s3, s4;
    	for (int i(0); i <H; i++) {
    		for (int j(0); j < W; j++) {
    			if (j) {
    				s1 = i * W + j - 1;
    				G.insertEdge(i*W + j, s1);
    			}
    			if (j < W - 1) {
    				s2 = i * W + j + 1;
    				G.insertEdge(i*W + j, s2);
    			}
    			s3 = (i -1)* W + j;
    			G.insertEdge(i*W + j, s3);
    			s4 = (i +1)* W + j;
    			G.insertEdge(i*W + j, s4);
    		}
    	}
    	int width = 500 / max(W, H);
    	CRect rect(200, 200, 200 + width * W, 200 + width * H);
    	int border = 5;
    	CBrush brush;
    	brush.CreateSolidBrush(RGB(255, 255,0));
    	DrawRect(rect, border, brush);
    	border = 2;
    	CBrush redbrush, blackbrush;
    	redbrush.CreateSolidBrush(RGB(255, 0, 0));
    	blackbrush.CreateSolidBrush(RGB(0, 0, 0));
    	for (int i(0); i < H; i++) {
    		for (int j(0); j < W; j++) {
    			CRect rect(200+j*width, 200+i*width, 200 + (j+1) * width, 200 + (i+1) * width);
    			if (feld[i][j] == '*') {
    				DrawRect(rect, border, redbrush);
    			}
    			else DrawRect(rect, border, blackbrush);
    			if (feld[i][j] == '@') {
    				CBrush greenbrush;
    				greenbrush.CreateSolidBrush(RGB(0,255,0));
    				DrawCircle(rect, border, greenbrush);
    			}
    		}
    	}
    	// TODO: 在此添加命令处理程序代码
    }
    

    用了画图的函数以后改代码也方便了很多

    5)DFS走格子动画显示

    其实这里也和上面的差不多,用到了栈

    void C走瓷砖View::Onstart()
    {
    	if (!is_OK) {
    		AfxMessageBox(_T("请先读取并绘制图"));
    		return;
    	}
    	int width = 500 / max(W, H);
    	int cur = Spos;
    	stack<int>P;
    	P.push(cur);
    	bool *vis= new bool[G.GetNodeNum()];
    	for (int i(0); i < G.GetNodeNum(); i++) {
    		vis[i] = false;
    	}
    	CBrush pinkbrush;
    	pinkbrush.CreateSolidBrush(RGB(255, 192,203));
    	int border = 2;
    	vis[cur] = true;
    	while (!P.empty()) {
    		cur = P.top();
    		P.pop();
    		CRect rect(200 + cur%W * width, 200 + (cur/W)* width, 200 + ((cur%W) + 1) * width, 200 + (cur / W + 1) * width);
    		DrawRect(rect, border, pinkbrush);
    		Sleep(50);
    		int w = G.getFirstNeighbor(cur);
    		if (w != -1) {
    			if (!vis[w] && G.getValue(w) == '#') {
    				P.push(w);
    				vis[w] = true;
    			}
    			int s = G.getNextNeighbor(cur, w);
    			while (s != -1) {
    				if (!vis[s] && G.getValue(s) == '#') {
    					P.push(s);
    					vis[s] = true;
    				}
    				s = G.getNextNeighbor(cur, s);
    			}
    		}
    	}
    	// TODO: 在此添加命令处理程序代码
    }
    

    6)房间数据哪里来?

    当然不能自己手写了,手写大了太累,再写个程序,生成房间瓷砖数据

    #include<iostream>
    #include<time.h>
    using namespace std;
    int main() {
    	int x;
    	srand(time(0));
    	while (cin >> x) {
    		int W = rand() % 20 + 5;
    		int H = W - rand() % 5;
    		cout << W << ' ' << H << ' ' << endl;
    		for (int i(0); i < H; i++) {
    			for (int j(0); j < W; j++) {
    				int s = rand() % 2;
    				if (s == 1)
    					cout << "*";
    				else cout << "#";
    			}
    			cout << endl;
    		}
    		cout << endl;
    	}
    	
    }
    

    只要随便输个数,就能生成一个图,然后选个你喜欢的地方,改成@起点,存在txt里就ok

    后记

    MFC其实还挺好玩的,(真香)
    就是脖子好疼
    2018/12/26 23:32:09

  • 相关阅读:
    真香!PySpark整合Apache Hudi实战
    Apache Hudi又双叕被国内顶级云服务提供商集成了!
    Apache Hudi集成Apache Zeppelin实战
    实战 | 将Apache Hudi数据集写入阿里云OSS
    实战|使用Spark Structured Streaming写入Hudi
    Apache Hudi 设计与架构最强解读
    【Flink】Flink作业调度流程分析
    【Flink】深入理解Flink-On-Yarn模式
    【Flink】Flink 底层RPC框架分析
    【MyBatis】MyBatis自动生成代码之查询爬坑记
  • 原文地址:https://www.cnblogs.com/Titordong/p/10182601.html
Copyright © 2011-2022 走看看