C++ 计算整数N内的所有排列,可以根据给定条件形成无环图
计数整数N以内的的整数贴标在非循环图表上需要研究所有可能的变化并检查他们是否满足给定条件的非循环图表。 这些情况可能与从这些变化形成的有序图结构相关联,其中没有循环表示无环性。这个问题涉及图论概念,可以通过深度优先搜索或动态规划来解决。深度优先搜索通过递归地探索每个节点,动态规划通过存储中间结果来优化循环。有效阶段的最终计数显示了整数N以内的整数可以如何组织以形成满足指定条件的非循环图表的方式数量。
使用的方法
- 深度优先搜索 (DFS)
-
动态规划
深度优先搜索 (DFS)
使用DFS方法生成给定操作的排列时,从给定数字开始,重复计算直到达到值1。具体操作如下:如果数字为偶数,则将其除以2;如果为奇数,则将其乘以3再加1。更新数字以反映未使用的结果,并将其加入排列。此过程持续到数字达到1。生成的排列代表给定起始数字的重复Collatz序列。这种方法允许我们通过重复计算跟踪数字的变化过程,揭示模式,并研究Collatz序列的行为。它提供了一种简单而可重复的方法来生成排列,并分析这一数学现象的有趣特点。
步骤
- 选择一个起始节点开始遍历。
-
将该节点标记为已访问,以便跟踪哪些节点已被主动探索。
-
访问当前节点的一个未访问过的邻居(如果有)。要确定当前节点的邻居,您需要了解图的连通性描述(例如邻接表或邻接矩阵)。
-
假设存在未访问的邻居,则选择其中一个并从该邻居开始重复步骤2到4(递归)。
-
假设没有未访问的邻居,回溯到前一个节点并从那里继续遍历(如果可能)。此步骤对于探索图中所有潜在路径至关重要。
-
重复步骤2到5,直到图中的所有节点都被访问。如果图不是连通的(包含多个连通分量),您可能需要从未访问的节点开始进行DFS。
示例
#include <iostream>
#include <vector>
using namespace std;
void dfs(int node, vector<vector<int>>& graph, vector<bool>& visited) {
visited[node] = true;
cout << "Visited hub: " << node << endl;
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
cout << "Moving to neighbor: " << neighbor << endl;
dfs(neighbor, graph, visited);
}
}
}
int main() {
vector<vector<int>> graph = {
{1, 2},
{0, 2, 3},
{0, 1, 3},
{1, 2, 4},
{3}
};
int hubs = graph.size();
vector<bool> visited(hubs, false);
int startingHub = 0;
cout << "DFS Traversal starting from hub " << startingHub << ":" << endl;
dfs(startingHub, graph, visited);
return 0;
}
输出
DFS Traversal starting from hub 0:
Visited hub: 0
Moving to neighbor: 1
Visited hub: 1
Moving to neighbor: 2
Visited hub: 2
Moving to neighbor: 3
Visited hub: 3
Moving to neighbor: 4
Visited hub: 4
动态规划
在这种方法中,我们可以利用动态规划来有效地计算从N循环到非循环阶段的数量。我们将定义一个DP表,其中dp[i]表示以数字I结束的非循环变化的数量。
步骤
- 研究问题并确定是否可以将其分解为较小的子问题。如果多次解决相同的子问题效率低下,使用动态规划可以通过记住子问题的解决方案来改进解决方案。
-
将更大问题的解决方案表示为其子问题的解决方案。这个递归关系是使用动态规划解决问题的关键。
-
根据递归关系,创建一个表或数组来存储子问题的解。这将防止重复计算。
-
从最小的子问题开始填充表格,通常是从底部向上,或者在递归过程中使用记忆化来存储和检索解。
-
当所有子问题都解决后,从DP表或记忆化数组中提取最终的解决方案。
示例
#include <iostream>
#include <vector>
using namespace std;
int knapsackHelper(vector<vector<int>>& dp, vector<int>& weights, vector<int>& values, int n, int capacity) {
if (n == 0 || capacity == 0) {
return 0;
}
if (dp[n][capacity] != -1) {
return dp[n][capacity];
}
if (weights[n - 1] <= capacity) {
dp[n][capacity] = max(values[n - 1] + knapsackHelper(dp, weights, values, n - 1, capacity - weights[n - 1]),
knapsackHelper(dp, weights, values, n - 1, capacity));
} else {
dp[n][capacity] = knapsackHelper(dp, weights, values, n - 1, capacity);
}
return dp[n][capacity];
}
int knapsack(vector<int>& weights, vector<int>& values, int capacity) {
int n = weights.size();
vector<vector<int>> dp(n + 1, vector<int>(capacity + 1, -1));
return knapsackHelper(dp, weights, values, n, capacity);
}
int main() {
vector<int> weights = {10, 20, 30};
vector<int> values = {60, 100, 120};
int capacity = 50;
cout << "Maximum value in Knapsack: " << knapsack(weights, values, capacity) << endl;
return 0;
}
输出
Maximum value in Knapsack: 220
结论
对于可以构造非循环图的阶段进行计数,包括研究从1到N的不同整数的计划,以确保它们满足给定的条件。DFS通过递归地探索阶段,而DP则通过记忆化来改进循环。这两种方法为解决这个问题提供了重要的策略。选择哪种方法取决于约束条件和N的大小。借助这些方法,我们可以高效地确定有效阶段的数量,从而帮助我们理解在给定条件下可以按照何种方式排列数字以构成非循环图。
极客笔记