グラフ理論のアルゴリズム実装ノート

1. 隣接行列を用いたDFS(再帰実装)

class GraphStructure {
public:
    GraphStructure(int nodes);
    void addConnection(int src, int dst);
    void traverseDFS(int startNode);

private:
    int nodeCount;
    vector<vector<int>> adjacencyMatrix;
    vector<bool> visitedFlags;

    void dfsRecursive(int current);
};

GraphStructure::GraphStructure(int nodes) {
    nodeCount = nodes;
    adjacencyMatrix.resize(nodes, vector<int>(nodes, 0));
    visitedFlags.assign(nodes, false);
}

// 無向グラフ
void GraphStructure::addConnection(int src, int dst) {
    adjacencyMatrix[src][dst] = 1;
    adjacencyMatrix[dst][src] = 1; 
}

void GraphStructure::traverseDFS(int startNode) {
    fill(visitedFlags.begin(), visitedFlags.end(), false);
    dfsRecursive(startNode);
    
    for (int i = 0; i < nodeCount; i++) {
        if (!visitedFlags[i])
            dfsRecursive(i);
    }
}

void GraphStructure::dfsRecursive(int current) {
    visitedFlags[current] = true;
    cout << "ノード訪問: " << current << endl;

    for (int i = 0; i < nodeCount; i++) {
        if (adjacencyMatrix[current][i] == 1 && !visitedFlags[i]) {
            dfsRecursive(i);
        }
    }
}

2. 隣接リストを用いたDFS(スタック実装)

class GraphList {
public:
    GraphList(int nodes);
    void addEdge(int src, int dst);
    void stackDFS(int start);

private:
    int vertexCount;
    vector<vector<int>> adjacencyList;
};

GraphList::GraphList(int nodes) {
    vertexCount = nodes;
    adjacencyList.resize(nodes);
}

// 無向グラフ
void GraphList::addEdge(int src, int dst) {
    adjacencyList[src].push_back(dst);
    adjacencyList[dst].push_back(src);
}

void GraphList::stackDFS(int start) {
    vector<bool> visited(vertexCount, false);
    stack<int> traversalStack;

    visited[start] = true;
    traversalStack.push(start);

    while (!traversalStack.empty()) {
        int current = traversalStack.top();
        traversalStack.pop();
        cout << "ノード訪問: " << current << endl;

        for (int neighbor : adjacencyList[current]) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                traversalStack.push(neighbor);
            }
        }
    }
}

3. 隣接リストを用いたBFS(キュー実装)

class GraphTraversal {
public:
    GraphTraversal(int nodes);
    void addLink(int src, int dst);
    void breadthFirstSearch(int start);

private:
    int totalNodes;
    vector<vector<int>> adjacencyList;
};

GraphTraversal::GraphTraversal(int nodes) {
    totalNodes = nodes;
    adjacencyList.resize(nodes);
}

// 無向グラフ
void GraphTraversal::addLink(int src, int dst) {
    adjacencyList[src].push_back(dst);
    adjacencyList[dst].push_back(src);
}

void GraphTraversal::breadthFirstSearch(int start) {
    vector<bool> visited(totalNodes, false);
    queue<int> searchQueue;

    visited[start] = true;
    searchQueue.push(start);

    while (!searchQueue.empty()) {
        int current = searchQueue.front();
        searchQueue.pop();
        cout << "ノード訪問: " << current << endl;

        for (int neighbor : adjacencyList[current]) {
            if (!visited[neighbor]) {
                visited[neighbor] = true;
                searchQueue.push(neighbor);
            }
        }
    }
}

4. 順方向スター構造によるDFS/BFS

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int MAX_VERTICES = 100000;

struct Connection {
    int destination;
    int weight;
    int nextIndex;
} connections[MAX_VERTICES];

int connectionHeads[MAX_VERTICES];
int edgeCount = 0;
int vertexTotal, edgeTotal;

void initialize() {
    fill(connectionHeads, connectionHeads + vertexTotal, -1);
    edgeCount = 0;
}

void createConnection(int from, int to, int weight) {
    connections[edgeCount].destination = to;
    connections[edgeCount].weight = weight;
    connections[edgeCount].nextIndex = connectionHeads[from];
    connectionHeads[from] = edgeCount++;
}

void depthFirst(int start) {
    vector<bool> visited(vertexTotal + 1, false);
    stack<int> dfsStack;
    
    dfsStack.push(start);
    visited[start] = true;
    
    while (!dfsStack.empty()) {
        int current = dfsStack.top();
        dfsStack.pop();
        cout << "ノード訪問: " << current << endl;
        
        for (int idx = connectionHeads[current]; idx != -1; idx = connections[idx].nextIndex) {
            int nextNode = connections[idx].destination;
            if (!visited[nextNode]) {
                dfsStack.push(nextNode);
                visited[nextNode] = true;
            }
        }
    }
}

void breadthFirst(int start) {
    vector<bool> visited(vertexTotal + 1, false);
    queue<int> bfsQueue;

    bfsQueue.push(start);
    visited[start] = true;

    while (!bfsQueue.empty()) {
        int current = bfsQueue.front();
        bfsQueue.pop();
        cout << "ノード訪問: " << current << endl;

        for (int idx = connectionHeads[current]; idx != -1; idx = connections[idx].nextIndex) {
            int nextNode = connections[idx].destination;
            if (!visited[nextNode]) {
                bfsQueue.push(nextNode);
                visited[nextNode] = true;
            }
        }
    }
}

5. 連結成分数の計算

	void countConnectedComponents() {
		visited.resize(nodeCount, false);
		componentCount = 0;

		for (int i = 0; i < nodeCount; i++) {
			if (!visited[i]) {
				recursiveDFS(i);
				componentCount++;
			}
		}
	}
	void recursiveDFS(int position) {
		visited[position] = true;
		for (int i = 0; i < nodeCount; i++) {
			if (adjacencyMatrix[position][i] == 1 && !visited[i]) {
				recursiveDFS(i);
			}
		}
	}

6. 最小全域木

最小全域木は重み付き連結無向グラフにおいて、すべての頂点を含みながら総コストが最小の部分木です。必須条件はn-1本の辺を含み、閉路を持たないこと。

Primアルゴリズム

class MinimumSpanningTree {
	int totalNodes;
	vector<vector<int>> weightedMatrix;
	map<string, int> nodeIndexMap;
	vector<int> visitedFlags;
	struct EdgeData {
		int sourceNode;
		int minimalCost;
	};

public:
	MinimumSpanningTree() {}

	void constructGraph() {
		int nodeNum;
		cin >> nodeNum;
		totalNodes = nodeNum;
		weightedMatrix.resize(totalNodes, vector<int>(totalNodes, INF));
		
		vector<string> nodeLabels(totalNodes);
		for (int i = 0; i < totalNodes; i++) {
			cin >> nodeLabels[i];
			nodeIndexMap[nodeLabels[i]] = i;
		}
		int edgeNum;
		cin >> edgeNum;
		for (int i = 0; i < edgeNum; i++) {
			string src, dst;
			int cost;
			cin >> src >> dst >> cost;
			addWeightedEdge(nodeIndexMap[src], nodeIndexMap[dst], cost);
		}
	}

	void addWeightedEdge(int src, int dst, int cost) {
		weightedMatrix[src][dst] = cost;
		weightedMatrix[dst][src] = cost;
	}

	int selectMinimum(vector<EdgeData> candidates) {
		int selectedIndex = -1, minCost = INF;
		for (int i = 0; i < totalNodes; i++) {
			if (minCost > candidates[i].minimalCost && candidates[i].minimalCost > 0) {
				minCost = candidates[i].minimalCost;
				selectedIndex = i;
			}
		}
		return selectedIndex;
	}

	void primAlgorithm(string initialNode) {
		int startIndex = nodeIndexMap[initialNode];
		int totalCost = 0;
		vector<int> selectedEdges;
		vector<EdgeData> edgeInfo(totalNodes);

		for (int i = 0; i < totalNodes; i++) {
			edgeInfo[i] = { startIndex, weightedMatrix[startIndex][i] };
		}

		edgeInfo[startIndex].minimalCost = 0;
		for (int i = 1; i < totalNodes; i++) {
			int selected = selectMinimum(edgeInfo);
			totalCost += edgeInfo[selected].minimalCost;
			selectedEdges.push_back(selected);

			edgeInfo[selected].minimalCost = 0;

			for (int j = 0; j < totalNodes; j++) {
				if (weightedMatrix[selected][j] < edgeInfo[j].minimalCost) {
					edgeInfo[j] = { selected, weightedMatrix[selected][j] };
				}
			}
		}

		cout << totalCost << endl;
		for (int i = 0; i < totalNodes - 1; i++) {
			int selected = selectedEdges[i];
			cout << nodeIndexMap[edgeInfo[selected].sourceNode] << " " << selected << " " << edgeInfo[selected].minimalCost << endl;
		}
	}
};

Kruskalアルゴリズム

class UnionFind {
	int size;
	vector<int> parentArray;
public:
	UnionFind(int size) {
		this->size = size;
		parentArray.resize(size);
		for (int i = 0; i < size; i++)
			parentArray[i] = i;
	}
	int findParent(int index) {
		if (parentArray[index] != index) return parentArray[index] = findParent(parentArray[index]);
		else return index;
	}
	void mergeSets(int first, int second) {
		parentArray[findParent(first)] = findParent(second);
		for (int i = 0; i < size; i++)
			findParent(i);
	}
	bool isSingleSet() {
		int root = parentArray[0];
		for (int i = 0; i < size; i++) {
			if (root != parentArray[i]) return false;
		}
		return true;
	}
};

class MSTKruskal {
	int totalNodes;
	vector<vector<int>> weightedMatrix;
	map<string, int> nodeIndexMap;

public:
	MSTKruskal() {}

	void constructGraph() {
		int nodeNum;
		cin >> nodeNum;
		totalNodes = nodeNum;
		weightedMatrix.resize(totalNodes, vector<int>(totalNodes, INF));
		
		vector<string> nodeLabels(totalNodes);
		for (int i = 0; i < totalNodes; i++) {
			cin >> nodeLabels[i];
			nodeIndexMap[nodeLabels[i]] = i;
		}
		int edgeNum;
		cin >> edgeNum;
		for (int i = 0; i < edgeNum; i++) {
			string src, dst;
			int cost;
			cin >> src >> dst >> cost;
			addWeightedEdge(nodeIndexMap[src], nodeIndexMap[dst], cost);
		}
	}

	void addWeightedEdge(int src, int dst, int cost) {
		weightedMatrix[src][dst] = cost;
		weightedMatrix[dst][src] = cost;
	}

	void findMinimumEdge(int &first, int &second, vector<vector<int>>& usedEdges) {
		int minCost = INF;
		for (int i = 0; i < totalNodes; i++) {
			for (int j = i+1; j < totalNodes; j++) {
				if (minCost > weightedMatrix[i][j] && usedEdges[i][j] == 0) {
					minCost = weightedMatrix[i][j];
					first = i, second = j;
				}
			}
		}
		usedEdges[first][second] = 1;
	}
	void kruskalAlgorithm(){
		vector<Edge> selectedEdges;
		vector<vector<int>> usedEdges(totalNodes, vector<int>(totalNodes,0));
		UnionFind unionFind(totalNodes);
		int totalCost = 0;

		int edgeCount = totalNodes * (totalNodes - 1) / 2;
		while (edgeCount--) {
			int u, v;
			findMinimumEdge(u, v, usedEdges);

			if (unionFind.findParent(u) != unionFind.findParent(v)) { 
				unionFind.mergeSets(u, v);
				selectedEdges.push_back({ u,v });
				totalCost += weightedMatrix[u][v];
			}
			
			if (unionFind.isSingleSet()) break;
		}
		if (!unionFind.isSingleSet()) {
			cout << -1 << endl;
		}
		else {
			cout << totalCost << endl;
			for (int i = 0; i < selectedEdges.size(); i++) {
				cout << nodeIndexMap[selectedEdges[i].from] << " " << nodeIndexMap[selectedEdges[i].to] << " " << weightedMatrix[selectedEdges[i].from][selectedEdges[i].to] << endl;
			}
		}
	}
	
};

7. 連結成分の森構築

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

// 森構造ノード
struct ForestNode{
    int value;
    vector<ForestNode*> children;
    ForestNode(int val) { value = val; }
};

vector<ForestNode*> forestRoots;

class GraphStructure {
public:
    GraphStructure(int nodes);
    void addConnection(int src, int dst);
    void buildForest();
    ForestNode* recursiveDFS(int current);

private:
    int nodeCount;
    vector<vector<int>> adjacencyMatrix;
    vector<bool> visitedFlags;
};

GraphStructure::GraphStructure(int nodes) {
    nodeCount = nodes;
    adjacencyMatrix.resize(nodes, vector<int>(nodes, 0));
    visitedFlags.assign(nodes, false);
}

// 無向グラフ
void GraphStructure::addConnection(int src, int dst) {
    adjacencyMatrix[src][dst] = 1;
    adjacencyMatrix[dst][src] = 1; 
}

void GraphStructure::buildForest() {
    visitedFlags.assign(nodeCount, false);

    for (int i = 0; i < nodeCount; i++) {
        if (!visitedFlags[i]) {
            ForestNode* root = recursiveDFS(i);
            forestRoots.push_back(root);
        }
    }
}

ForestNode* GraphStructure::recursiveDFS(int current) {
    visitedFlags[current] = true;
    ForestNode* currentNode = new ForestNode(current);

    for (int i = 0; i < nodeCount; i++) {
        if (adjacencyMatrix[current][i] == 1 && !visitedFlags[i]) {
            currentNode->children.push_back(recursiveDFS(i));
        }
    }
    return currentNode;
}

void displayForest(ForestNode *node) {
    cout << node->value;
    for (int i = 0; i < node->children.size(); i++) {
        if(node != nullptr)
            displayForest(node->children[i]);
    }
}

8. 最短経路探索(Dijkstraアルゴリズム)

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;

class ShortestPath {
	int nodeCount;
	vector<vector<int>> weightedMatrix;
	map<string, int> nodeIndexMap;
	vector<int> visitedFlags;

public:
	ShortestPath() {}

	void constructGraph() {
		int nodeNum;
		cin >> nodeNum;
		nodeCount = nodeNum;
		weightedMatrix.assign(nodeCount, vector<int>(nodeCount));

		vector<string> nodeLabels(nodeCount);
		for (int i = 0; i < nodeCount; i++) {
			cin >> nodeLabels[i];
			nodeIndexMap[nodeLabels[i]] = i;
		}

		for (int i = 0; i < nodeCount; i++) {
			for (int j = 0; j < nodeCount; j++) {
				int weight;
				cin >> weight;
				addWeightedEdge(i, j, weight);
			}
		}
	}

	void addWeightedEdge(int src, int dst, int weight) {
		weightedMatrix[src][dst] = weight;
	}

	void dijkstraAlgorithm() {
		vector<queue<int>> pathRecords(nodeCount);
		visitedFlags.assign(nodeCount, 0);
		vector<int> distances(nodeCount, INF);

		string startNode;
		cin >> startNode;
		int start = nodeIndexMap[startNode];
		visitedFlags[start] = 1;
		distances[start] = 0;
		for (int i = 0; i < nodeCount; i++) {
			if(weightedMatrix[start][i])
			{
				distances[i] = distances[start] + weightedMatrix[start][i];
				pathRecords[i].push(start);
			}
		}

		for (int i = 0; i < nodeCount - 1; i++) {
			int minDistance = INF;
			for (int j = 0; j < nodeCount; j++)
				if (!visitedFlags[j] && minDistance > distances[j])
				{
					start = j;
					minDistance = distances[j];
				}
			visitedFlags[start] = 1;

			for (int j = 0; j < nodeCount; j++) {
				if (!visitedFlags[j] && weightedMatrix[start][j] && minDistance + weightedMatrix[start][j] < distances[j]) {
					pathRecords[j] = pathRecords[start];
					pathRecords[j].push(start);
					distances[j] = minDistance + weightedMatrix[start][j];
				}
			}
		}

		for (int i = 0; i < nodeCount; i++) {
			if (i != nodeIndexMap[startNode]) {
				cout << startNode << "-" << nodeLabels[i] << "-";
				if (distances[i] == INF) {
					cout << "-1" << endl;
				}
				else {
					cout << distances[i] << "----[";
					while(!pathRecords[i].empty()) {
						cout << nodeLabels[pathRecords[i].front()] << " ";
						pathRecords[i].pop();
					}
					cout << nodeLabels[i] << " ]" << endl;
				}
			}
		}
	}
};

9. 正の閉路検出(通貨交換問題)

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;

class ArbitrageDetection {
	int nodeCount;
	vector<vector<double>> exchangeRates;
	map<string, int> nodeIndexMap;
	vector<int> visitedFlags;
	vector<vector<double>> pathValues;
	bool hasArbitrage;

public:
	ArbitrageDetection() {}

	void constructGraph() {
		int nodeNum;
		cin >> nodeNum;
		nodeCount = nodeNum;
		exchangeRates.assign(nodeCount, vector<double>(nodeCount, 0));
		int edgeNum;
		cin >> edgeNum;

		vector<string> nodeLabels(nodeCount);
		for (int i = 0; i < nodeCount; i++) {
			cin >> nodeLabels[i];
			nodeIndexMap[nodeLabels[i]] = i;
		}

		for (int i = 0; i < edgeNum; i++) {
			string src, dst;
			double rate;
			cin >> src >> rate >> dst;
			addExchangeRate(nodeIndexMap[src], nodeIndexMap[dst], rate);
		}
	}

	void addExchangeRate(int src, int dst, double rate) {
		exchangeRates[src][dst] = rate;
	}


	bool detectArbitrage() {
		visitedFlags.assign(nodeCount, 0);
		pathValues.assign(nodeCount, vector<double>(nodeCount, 0));
		hasArbitrage = false;

		for (int i = 0; i < nodeCount; i++) {
			pathValues[i][i] = 1;
			for (int j = 0; j < nodeCount; j++) {
				if (i != j) pathValues[i][j] = 0;
			}
		}

		for (int i = 0; i < nodeCount; i++) {
			if (!visitedFlags[i])
				recursiveDFS(i);
			if (hasArbitrage) return true;
		}
		return false;
	}

	void recursiveDFS(int current) {
		visitedFlags[current] = 1;

		for (int i = 0; i < nodeCount; i++) {

			if (exchangeRates[current][i] && visitedFlags[i]) {  
				if (pathValues[i][current] * exchangeRates[current][i] > 1) hasArbitrage = true;
				continue;
			}
			else if(exchangeRates[current][i]){
				for (int j = 0; j < nodeCount; j++) {
					pathValues[j][i] = pathValues[j][current] * exchangeRates[current][i];
				}
				recursiveDFS(i);
			}
		}
	}
};

10. キー経路分析(AOEネットワーク)

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;

class CriticalPathAnalysis {
	int nodeCount;
	vector<vector<int>> activityMatrix;
	vector<int> earliestStart;
	vector<int> latestStart;
	stack<int> topologicalOrder;
	queue<int> processingQueue;
	vector<int> incomingDegrees;

public:
	CriticalPathAnalysis() {}

	void constructNetwork() {
		int nodeNum;
		cin >> nodeNum;
		nodeCount = nodeNum;
		activityMatrix.assign(nodeCount, vector<int>(nodeCount, 0));
		incomingDegrees.assign(nodeCount, 0);

		int edgeNum;
		cin >> edgeNum;
		for (int i = 0; i < edgeNum; i++) {
			int u, v, duration;
			cin >> u >> v >> duration;
			activityMatrix[u][v] = duration;
			incomingDegrees[v]++;
		}
	}

	void topologicalSort() {
		for (int i = 0; i < nodeCount; i++) {
			if (incomingDegrees[i] == 0) processingQueue.push(i);
		}
		
		earliestStart.assign(nodeCount, 0);

		while (!processingQueue.empty()) {
			int current = processingQueue.front();
			topologicalOrder.push(current);
			processingQueue.pop();
			for (int i = 0; i < nodeCount; i++) {
				if (activityMatrix[current][i] != 0) {
					incomingDegrees[i]--;
					if (incomingDegrees[i] == 0) processingQueue.push(i);
					if (earliestStart[current] + activityMatrix[current][i] > earliestStart[i]) earliestStart[i] = earliestStart[current] + activityMatrix[current][i];
				}
			}
		}

		for (int i = 0; i < nodeCount; i++) {
			cout << earliestStart[i] << " ";
		}
		cout << endl;

	}
	void identifyCriticalPath() {
		latestStart.assign(nodeCount, earliestStart[topologicalOrder.top()]); 

		while (!topologicalOrder.empty()) {
			int current = topologicalOrder.top();
			topologicalOrder.pop();
			for (int i = 0; i < nodeCount; i++) {
				if (activityMatrix[i][current] != 0) {
					if (latestStart[current] - activityMatrix[i][current] < latestStart[i]) latestStart[i] = latestStart[current] - activityMatrix[i][current];
				}
			}
		}

		for (int i = 0; i < nodeCount; i++) {
			cout << latestStart[i] << " ";
		}
		cout << endl;

		for (int i = 0; i < nodeCount; i++) {
			if (i == nodeCount - 1) cout << i << endl;
			if (earliestStart[i] == latestStart[i] && i < nodeCount - 1) cout << i << "->";
		}
	}
};

11. 旅行計画

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;

class TravelRoute {
	int nodeCount;
	struct Highway {
		int distance;
		int toll;
	};
	vector<vector<Highway>> roadNetwork;
	vector<int> visitedFlags;
	int sourceNode, destinationNode;

public:
	TravelRoute() {}

	void constructMap() {
		int nodeNum;
		cin >> nodeNum;
		nodeCount = nodeNum;
		roadNetwork.assign(nodeCount, vector<Highway>(nodeCount, {0,0}));

		int edgeNum;
		cin >> edgeNum;

		cin >> sourceNode >> destinationNode;

		for (int i = 0; i < edgeNum; i++) {
			int u, v, w, c;
			cin >> u >> v >> w >> c;
			addHighway(u, v, w, c);
		}
	}

	void addHighway(int src, int dst, int w, int c) {
		roadNetwork[src][dst].distance = w;
		roadNetwork[src][dst].toll = c;
	}

	void optimizeRoute() {
		vector<int> tollCosts(nodeCount, 0);
		visitedFlags.assign(nodeCount, 0);
		vector<int> distances(nodeCount, INF);

		int current = sourceNode;
		visitedFlags[current] = 1;
		distances[current] = 0;
		tollCosts[current] = 0;
		
		for (int i = 0; i < nodeCount; i++) {
			if(roadNetwork[current][i].distance)
			{
				distances[i] = distances[current] + roadNetwork[current][i].distance;
				tollCosts[i] += roadNetwork[current][i].toll;
			}
		}

		for (int i = 0; i < nodeCount - 1; i++) {
			int minDistance = INF;
			for (int j = 0; j < nodeCount; j++)
				if (!visitedFlags[j] && minDistance > distances[j])
				{
					current = j;
					minDistance = distances[j];
				}
			visitedFlags[current] = 1;

			int minToll;
			for (int j = 0; j < nodeCount; j++) {
				minToll = INF;
				if (!visitedFlags[j] && roadNetwork[current][j].distance && minDistance + roadNetwork[current][j].distance <= distances[j]) {
					if (minDistance + roadNetwork[current][j].distance == distances[j] && tollCosts[current] + roadNetwork[current][j].toll < minToll) minToll = tollCosts[current] + roadNetwork[current][j].toll;
					distances[j] = minDistance + roadNetwork[current][j].distance;
				}
				if(minToll != INF) tollCosts[j] = minToll;
			}
		}
		cout << distances[destinationNode] << " " << tollCosts[destinationNode];
	}
};

12. 007の救出(座標変換)

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;

class EscapeSimulation {
	int nodeCount;
	vector<vector<int>> connectivityMatrix;
	struct Coordinate {
		int x, y;
		Coordinate() {}
		Coordinate(int xx, int yy) { x = xx, y = yy; }
	};
	vector<int> visitedFlags;
	int safetyDistance;
	vector<Coordinate> positions;
	bool canEscape;

public:
	EscapeSimulation() {}

	void setupScenario() {
		int crocodileCount;
		cin >> crocodileCount;
		nodeCount = crocodileCount + 1;
		connectivityMatrix.assign(nodeCount + 1, vector<int>(nodeCount + 1, 0));
		cin >> safetyDistance;

		for (int i = 0; i < crocodileCount; i++) {
			int x, y;
			cin >> x >> y;
			positions.push_back(Coordinate{ x,y });
		}
		positions.push_back(Coordinate{ 0,0 });

		for (int i = 0; i < crocodileCount; i++) {
			for (int j = 0; j < crocodileCount; j++) {
				if (i == j || distanceBetween(positions[i], positions[j]) > safetyDistance) connectivityMatrix[i][j] = 0;
				else if (distanceBetween(positions[i], positions[j]) <= safetyDistance) {
					connectivityMatrix[i][j] = 1;
					connectivityMatrix[j][i] = 1;
				}
			}
		}
		for (int i = 0; i < crocodileCount; i++) {
			if (positions[i].x*positions[i].x + positions[i].y * positions[i].y  <= (7.5 + safetyDistance)*(7.5 + safetyDistance)) {
				connectivityMatrix[crocodileCount][i] = 1;
			}
			else {
				connectivityMatrix[crocodileCount][i] = 0;	
			}
		}
		connectivityMatrix[crocodileCount][crocodileCount] = 0;
	}

	double distanceBetween(Coordinate a, Coordinate b) {
		return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
	}

	void addConnection(int src, int dst, int value) {
		connectivityMatrix[src][dst] = value;
	}
	bool isOnShore(Coordinate p) {
		if (p.x - (-50) <= safetyDistance || 50 - p.x <= safetyDistance || p.y - (-50) <= safetyDistance || 50 - p.y <= safetyDistance) {
			return true;
		}
		else return false;
	}


	bool attemptEscape() {

		visitedFlags.assign(nodeCount, 0);
		canEscape = false;

		for (int i = 0; i < nodeCount - 1; i++)
		{
			if (!visitedFlags[i] && connectivityMatrix[nodeCount - 1][i])  
			{
				recursiveDFS(i);
			}
			if (canEscape) return true;
		}
		return false;
	}

	void recursiveDFS(int current) {
		visitedFlags[current] = 1;
		if (isOnShore(positions[current]) || canEscape)
		{
			canEscape = true; return;
		}
		for (int i = 0; i < nodeCount - 1; i++)
		{
			if (!visitedFlags[i] && connectivityMatrix[current][i])
			{
				recursiveDFS(i);
			}
		}

	}
};

13. サイクル検出

無向グラフ: 度数1の頂点を順に削除し、関連頂点の度数を減らす。最終的に度数>1の頂点が存在すればサイクルあり。

有向グラフ: 入次数0の頂点を順に削除し、関連頂点の入次数を減らす。最終的に入次数≠0の頂点が存在すればサイクルあり。

// 無向グラフのサイクル検出

#include<bits/stdc++.h>
#define MAX_NODES 100010
using namespace std;

vector<vector<int>> graph;
int nodeCount;
vector<int> degrees;

int main()
{
    cin >> nodeCount;
    degrees.resize(nodeCount + 1, 0);
    graph.resize(nodeCount + 1);
    for (int i = 1; i <= nodeCount; i++) {
        int a, b;
        cin >> a >> b;
        degrees[a]++, degrees[b]++;
        graph[a].push_back(b);
        graph[b].push_back(a);
    }

    queue<int> leafNodes;
    for (int i = 1; i <= nodeCount; i++) {
        if (degrees[i] == 1) leafNodes.push(i);
    }
    while (!leafNodes.empty()) {
        int current = leafNodes.front();
        leafNodes.pop();
        for (int i = 0; i < graph[current].size(); i++) {
            int connected = graph[current][i];
            degrees[connected]--;
            if (degrees[connected] == 1) {
                leafNodes.push(connected);
            }
        }
    }
    for (int i = 1; i <= nodeCount; i++) {
        if (degrees[i] > 1) cout << i << " ";
    }
    return 0;
}

タグ: C++ グラフ理論 DFS BFS 最小全域木

6月15日 20:13 投稿