APCS程式檢測 -實作題1050305 第4題 血緣關係(進階思考)

APCS程式檢測 -實作題1050305 第4題 血緣關係(進階思考)

上一篇
APCS程式檢測 -實作題1050305 第4題 血緣關係
https://husking-studio.com/apcs-1050305-4/

試著印出路徑看看
加入 PrintPath 相關程式碼

完整程式碼

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

//樹的基本結構和功能
void AddChild(int** pTree, int nRow, int nCol, int nParent, int nChild);	//加入節點
int GetLeafNum(int** pTree, int nRow, int nCol);	//取得葉子節點的數量
int FindRoot(int** pTree, int nRow, int nCol);		//找出根節點
int GetChildNum(int** pTree, int nRow, int nCol, int nNode);	//取得某節點的孩子數量
int Distance(int** pTree, int nRow, int nCol, int nNode);	//取得某節點的高度
void PrintTree(int** pTree, int nRow, int nCol);	//印出

//
void SetLeaf(int** pTree, int nRow, int nCol, int* pLeaf);
void SetParent(int** pTree, int nRow, int nCol, int** pParentTree, int nParentRow, int nParentCol);
void FindParent(int** pTree, int nRow, int nCol, int nChild, int* pParent, int nParentRow, int nParentCol, int k);
int GetMaxDistance(int** pParentTree, int nParentRow, int nParentCol, int* pLeaf, int nLeafNum);
int GetPairDistance(int** pParentTree, int nParentRow, int nParentCol, int nA, int nB);

//印出路徑相關
void PrintPath(int** pTree, int nRow, int nCol, int** pParentTree, int nParentRow, int nParentCol, int* pLeaf, int nLeafNum);
int GetMaxDistance2(int** pParentTree, int nParentRow, int nParentCol, int* pLeaf, int nLeafNum, int* nA, int* nB);
int GetPairDistance2(int** pParentTree, int nParentRow, int nParentCol, int nA, int nB, int* nParent);

int main()
{
	//處理輸入-n個節點
	string strInput;
	getline(cin, strInput);
	int n = stoi(strInput);

	//
	int* pChildNum = new int[n];
	for (int i = 0; i < n; i++)
		pChildNum[i] = 0;

	//將接下來的輸入存在 vector 裡
	vector<string> vecInput;
	for (int i = 0; i < (n - 1); i++)
	{
		int nParentNode = -1;
		getline(cin, strInput);

		stringstream delim(strInput);
		string pch;

		getline(delim, pch, ' ');
		nParentNode = stoi(pch);

		getline(delim, pch, ' ');

		pChildNum[nParentNode]++;
		vecInput.push_back(strInput);
	}
	//
	int nMaxChildNum = 0;
	for (int i = 0; i < n; i++)
	{
		if (pChildNum[i] > nMaxChildNum)
			nMaxChildNum = pChildNum[i];
	}

	delete[] pChildNum;

	//
	int nTreeRow = n;
	int nTreeCol = nMaxChildNum;

	//宣告
	int** pTree;
	pTree = new int* [nTreeRow];
	for (int i = 0; i < nTreeRow; i++)
		pTree[i] = new int[nTreeCol];

	//初始化
	for (int i = 0; i < nTreeRow; i++)
		for (int j = 0; j < nTreeCol; j++)
			pTree[i][j] = -1;

	//加入資料
	for (int i = 0; i < (int)vecInput.size(); i++)
	{
		int nParentNode = -1;
		int nChildNode = -1;

		stringstream delim(vecInput[i]);
		string pch;

		getline(delim, pch, ' ');
		nParentNode = stoi(pch);

		getline(delim, pch, ' ');
		nChildNode = stoi(pch);

		AddChild(pTree, nTreeRow, nTreeCol, nParentNode, nChildNode);
	}

	//找葉子節點,存在 pLeaf 陣列裡
	int nLeafNum = GetLeafNum(pTree, nTreeRow, nTreeCol);
	int* pLeaf = new int[nLeafNum];
	SetLeaf(pTree, nTreeRow, nTreeCol, pLeaf);

	//找根節點
	int nRoot = FindRoot(pTree, nTreeRow, nTreeCol);
	//深度
	int nDepth = Distance(pTree, nTreeRow, nTreeCol, nRoot);

	//父連結
	int nParentTreeRow = nTreeRow;
	int nParentTreeCol = nDepth;

	//建立父連結資料
	int** pParentTree;
	pParentTree = new int* [nParentTreeRow];
	for (int i = 0; i < nParentTreeRow; i++)
		pParentTree[i] = new int[nParentTreeCol];

	//初始化
	for (int i = 0; i < nParentTreeRow; i++)
		for (int j = 0; j < nParentTreeCol; j++)
			pParentTree[i][j] = -1;

	//建立父連結陣列
	SetParent(pTree, nTreeRow, nTreeCol, pParentTree, nParentTreeRow, nParentTreeCol);

	//印出路徑
	PrintPath(pTree, nTreeRow, nTreeCol, pParentTree, nParentTreeRow, nParentTreeCol, pLeaf, nLeafNum);

	//delete
	for (int i = 0; i < nParentTreeRow; i++)
		delete[] pParentTree[i];
	delete[] pParentTree;
	delete[] pLeaf;
	for (int i = 0; i < nTreeRow; i++)
		delete[] pTree[i];
	delete[] pTree;

	system("pause");
	return 0;
}
int GetPairDistance(int** pParentTree, int nParentRow, int nParentCol, int nA, int nB)
{
	int* pRowA = pParentTree[nA];
	int* pRowB = pParentTree[nB];
	int nMaxDistance = 0;
	int nTempDistance = 0;

	int a2 = 0;
	int b2 = 0;

	bool bFind = false;

	for (int a = 0; a < nParentCol; a++)
	{
		for (int b = 0; b < nParentCol; b++)
		{
			if (pRowA[a] == pRowB[b])		//找共同父節點
			{
				a2 = a + 1;
				b2 = b + 1;

				bFind = true;
				break;
			}
		}
		if (bFind)
			break;
	}

	if (bFind)
	{
		nTempDistance = a2 + b2;
		if (nTempDistance > nMaxDistance)
			nMaxDistance = nTempDistance;
	}

	return nMaxDistance;
}
int GetMaxDistance(int** pParentTree, int nParentRow, int nParentCol, int* pLeaf, int nLeafNum)
{
	int nMaxDistance = 0;
	int nTempDistance = 0;

	//在葉子節點中捉對
	for (int i = 0; i < nLeafNum; i++)
	{
		for (int j = i + 1; j < nLeafNum; j++)
		{
			nTempDistance = GetPairDistance(pParentTree, nParentRow, nParentCol, pLeaf[i], pLeaf[j]);
			if (nTempDistance > nMaxDistance)
				nMaxDistance = nTempDistance;
		}
	}
	return nMaxDistance;
}
void SetParent(int** pTree, int nRow, int nCol, int** pParentTree, int nParentRow, int nParentCol)
{
	int k = 0;
	for (int i = 0; i < nRow; i++)
	{
		k = 0;
		FindParent(pTree, nRow, nCol, i, pParentTree[i], nParentRow, nParentCol, k);
	}
}
void FindParent(int** pTree, int nRow, int nCol, int nChild, int* pParent, int nParentRow, int nParentCol, int k)
{
	bool bFind = false;
	for (int i = 0; i < nRow; i++)
	{
		for (int j = 0; j < nCol; j++)
		{
			if (pTree[i][j] == nChild)
			{
				bFind = true;
				pParent[k] = i;
				FindParent(pTree, nRow, nCol, i, pParent, nParentRow, nParentCol, k + 1);
			}
		}
	}
	if (bFind == false)
		return;
}
void SetLeaf(int** pTree, int nRow, int nCol, int* pLeaf)
{
	int k = 0;
	bool bAll = true;

	for (int i = 0; i < nRow; i++)
	{
		bAll = true;
		for (int j = 0; j < nCol; j++)
		{
			if (pTree[i][j] != -1)
			{
				bAll = false;
				break;
			}
		}
		if (bAll)
		{
			pLeaf[k] = i;
			k++;
		}
	}
}
//取得某節點的高度
int Distance(int** pTree, int nRow, int nCol, int nNode)
{
	int nChildNum = GetChildNum(pTree, nRow, nCol, nNode);
	if (nChildNum == 0)
		return 0;

	int nDepthMax = 0;
	int nDepth = 0;
	int* pRow = pTree[nNode];
	for (int k = 0; k < nChildNum; k++)
	{
		nDepth = Distance(pTree, nRow, nCol, pRow[k]) + 1;
		if (nDepth > nDepthMax)
			nDepthMax = nDepth;
	}
	return nDepthMax;
}
//取得某節點的孩子數量
int GetChildNum(int** pTree, int nRow, int nCol, int nNode)
{
	int nChildNum = 0;
	int* pRow = pTree[nNode];

	for (int j = 0; j < nCol; j++)
	{
		if (pRow[j] != -1)
			nChildNum++;
	}
	return nChildNum;
}
//取得葉子節點的數量
int GetLeafNum(int** pTree, int nRow, int nCol)
{
	int nLeafNum = 0;
	bool bHaveChild = false;

	for (int i = 0; i < nRow; i++)
	{
		bHaveChild = false;
		for (int j = 0; j < nCol; j++)
		{
			if (pTree[i][j] != -1)
			{
				bHaveChild = true;
				break;
			}
		}
		if (bHaveChild == false)
			nLeafNum++;
	}
	return nLeafNum;
}
//找出根節點
int FindRoot(int** pTree, int nRow, int nCol)
{
	bool* bNode = new bool[nRow];
	for (int i = 0; i < nRow; i++)
		bNode[i] = false;

	for (int i = 0; i < nRow; i++)
	{
		for (int j = 0; j < nCol; j++)
		{
			if (pTree[i][j] != -1)
				bNode[pTree[i][j]] = true;
		}
	}

	int nRoot = -1;
	for (int i = 0; i < nRow; i++)
	{
		if (bNode[i] == false)
		{
			nRoot = i;
			break;
		}
	}

	delete[] bNode;

	return nRoot;
}
//加入節點
void AddChild(int** pTree, int nRow, int nCol, int nParent, int nChild)
{
	int* pRow = pTree[nParent];

	for (int j = 0; j < nCol; j++)
	{
		if (pRow[j] == -1)
		{
			pRow[j] = nChild;
			break;
		}
	}
}
//印出
void PrintTree(int** pTree, int nRow, int nCol)
{
	for (int i = 0; i < nRow; i++)
	{
		cout << "node(" << i << ")->";
		for (int j = 0; j < nCol; j++)
		{
			cout << pTree[i][j] << " ";
		}
		cout << endl;
	}
}
void PrintPath(int** pTree, int nRow, int nCol, int** pParentTree, int nParentRow, int nParentCol, int* pLeaf, int nLeafNum)
{
	//取得最遠的葉子節點距離
	int nA = -1;	//最遠的葉子節點1
	int nB = -1;	//最遠的葉子節點2
	GetMaxDistance2(pParentTree, nParentRow, nParentCol, pLeaf, nLeafNum, &nA, &nB);

	//
	int nParent = -1;	//共同的父節點
	int nDistance = GetPairDistance2(pParentTree, nParentRow, nParentCol, nA, nB, &nParent);

	//
	cout << nA << "->";
	int* pA = pParentTree[nA];
	for (int j = 0; j < nParentCol; j++)
	{
		cout << pA[j] << "->";
		if (pA[j] == nParent)
			break;
	}

	//
	int* pB = pParentTree[nB];
	bool bPrint = false;
	for (int j = (nParentCol - 1); j >= 0; j--)
	{
		if (bPrint)
			cout << pB[j] << "->";

		if (pB[j] == nParent)
			bPrint = true;
	}
	cout << nB << endl;
}
int GetMaxDistance2(int** pParentTree, int nParentRow, int nParentCol, int* pLeaf, int nLeafNum, int* nA, int* nB)
{
	int nMaxDistance = 0;
	int nTempDistance = 0;

	//在葉子節點中捉對
	for (int i = 0; i < nLeafNum; i++)
	{
		for (int j = i + 1; j < nLeafNum; j++)
		{
			nTempDistance = GetPairDistance(pParentTree, nParentRow, nParentCol, pLeaf[i], pLeaf[j]);
			if (nTempDistance > nMaxDistance)
			{
				*nA = pLeaf[i];
				*nB = pLeaf[j];
				nMaxDistance = nTempDistance;
			}
		}
	}
	return nMaxDistance;
}
int GetPairDistance2(int** pParentTree, int nParentRow, int nParentCol, int nA, int nB, int* nParent)
{
	int* pRowA = pParentTree[nA];
	int* pRowB = pParentTree[nB];
	int nMaxDistance = 0;
	int nTempDistance = 0;

	int a2 = 0;
	int b2 = 0;

	bool bFind = false;

	for (int a = 0; a < nParentCol; a++)
	{
		for (int b = 0; b < nParentCol; b++)
		{
			if (pRowA[a] == pRowB[b])		//找共同父節點
			{
				a2 = a + 1;
				b2 = b + 1;

				*nParent = pRowA[a];

				bFind = true;
				break;
			}
		}
		if (bFind)
			break;
	}

	if (bFind)
	{
		nTempDistance = a2 + b2;
		if (nTempDistance > nMaxDistance)
			nMaxDistance = nTempDistance;
	}

	return nMaxDistance;
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *