当前位置: 首页 > wzjs >正文

江苏建设工程招投标网站市场调研报告怎么写范文

江苏建设工程招投标网站,市场调研报告怎么写范文,衡阳网站推广排名,邯郸市城市建设局网站P5318 【深基18.例3】查找文献 解题思路 图的构建:使用邻接表存储每个文献的引用关系。读取输入后,对每个节点的邻接表进行排序和去重,以确保节点按升序排列。 DFS遍历:使用栈来实现非递归遍历。每次从栈中弹出节点后&#xff0…

P5318 【深基18.例3】查找文献

解题思路

  1. 图的构建:使用邻接表存储每个文献的引用关系。读取输入后,对每个节点的邻接表进行排序和去重,以确保节点按升序排列。

  2. DFS遍历:使用栈来实现非递归遍历。每次从栈中弹出节点后,将其邻接节点逆序压入栈中,以确保优先处理编号较小的节点。

  3. BFS遍历:使用队列来实现广度优先搜索。按邻接表的顺序处理节点,确保先访问编号较小的节点。

  4. 结果输出:将DFS和BFS的遍历结果格式化为字符串并输出。

import java.util.*;
import java.io.*;public class Main {public static void main(String[] args) throws IOException {// 使用 StreamTokenizer 读取输入StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));st.nextToken();int n = (int) st.nval; // 读取文章数量 nst.nextToken();int m = (int) st.nval; // 读取引用关系数量 m// 初始化邻接表,用于存储图的引用关系List<List<Integer>> adj = new ArrayList<>(n + 1);for (int i = 0; i <= n; i++) {adj.add(new ArrayList<>());}// 读取引用关系并存储到邻接表中for (int i = 0; i < m; i++) {st.nextToken();int X = (int) st.nval; // 文章 Xst.nextToken();int Y = (int) st.nval; // 文章 Yadj.get(X).add(Y); // 表示 X 指向 Y}// 对每个邻接表进行排序和去重,保证编号较小的文章优先访问for (int i = 1; i <= n; i++) {List<Integer> list = adj.get(i);if (list.isEmpty()) continue; // 如果没有引用关系,跳过Collections.sort(list); // 对邻接表排序// 去重操作int j = 0;for (int k = 1; k < list.size(); k++) {if (!list.get(k).equals(list.get(j))) {j++;list.set(j, list.get(k));}}if (list.size() > j + 1) {list.subList(j + 1, list.size()).clear(); // 删除多余的元素}}// 深度优先搜索 (DFS)boolean[] visited = new boolean[n + 1]; // 访问标记数组List<Integer> dfsOrder = new ArrayList<>(); // 存储 DFS 遍历结果Deque<Integer> stack = new ArrayDeque<>(); // 使用栈实现 DFSstack.push(1); // 从编号为 1 的文章开始while (!stack.isEmpty()) {int u = stack.pop(); // 弹出栈顶元素if (visited[u]) continue; // 如果已经访问过,跳过visited[u] = true; // 标记为已访问dfsOrder.add(u); // 记录访问顺序List<Integer> neighbors = adj.get(u); // 获取当前节点的邻居// 倒序遍历邻居,保证编号较小的优先被访问for (int i = neighbors.size() - 1; i >= 0; i--) {int v = neighbors.get(i);if (!visited[v]) {stack.push(v); // 将未访问的邻居压入栈}}}// 广度优先搜索 (BFS)visited = new boolean[n + 1]; // 重置访问标记数组List<Integer> bfsOrder = new ArrayList<>(); // 存储 BFS 遍历结果Queue<Integer> queue = new LinkedList<>(); // 使用队列实现 BFSqueue.offer(1); // 从编号为 1 的文章开始visited[1] = true; // 标记起点为已访问while (!queue.isEmpty()) {int u = queue.poll(); // 取出队首元素bfsOrder.add(u); // 记录访问顺序for (int v : adj.get(u)) { // 遍历当前节点的邻居if (!visited[v]) {visited[v] = true; // 标记为已访问queue.offer(v); // 将未访问的邻居加入队列}}}// 输出结果StringBuilder sb = new StringBuilder();for (int num : dfsOrder) {sb.append(num).append(' '); // 拼接 DFS 遍历结果}sb.append('\n');for (int num : bfsOrder) {sb.append(num).append(' '); // 拼接 BFS 遍历结果}System.out.print(sb); // 输出最终结果}
}

P3916 图的遍历

解题思路

  • 图的表示

    • 使用邻接表表示有向图。由于题目要求找到从每个节点能到达的最大编号节点,因此可以构建图的反向边。
    • 在反向图中,如果存在一条边 (u, v),则在图中加入边 (v, u),这样我们可以从目标节点向源节点遍历。
  • 遍历策略

    • 为了计算每个节点的最大可达编号,我们可以采用深度优先搜索(DFS)。
    • 从每个节点开始 DFS 时,如果当前节点已经被访问过,直接返回已存储的结果;否则,记录从该节点出发的最大可达编号。
    • 为了确保每个节点的 DFS 都能得到准确的最大编号,可以从编号较大的节点开始 DFS。
  • 结果存储

    • 使用一个数组 num 来存储每个节点的最大可达编号,数组的索引对应节点编号。
    • 当遍历结束后,数组 num 中的每个元素即为所求结果。
import java.util.*;public class Main {static int MAXL = 100001;           // 最大点数static int n, m;                    // 节点数和边数static int[] num = new int[MAXL];      // 记录从每个节点出发到达的最大节点编号static List<List<Integer>> g = new ArrayList<>();          // 邻接表public static void main(String[] args) {Scanner input = new Scanner(System.in);// 读取点数和边数n = input.nextInt();m = input.nextInt();// 初始化邻接表for (int i = 0; i <= n; i++) {g.add(new ArrayList<>());   // 为每个节点创建一个列表}// 反向建边for (int i = 0; i < m; i++) {// 边的起点int u = input.nextInt();// 边的终点int v = input.nextInt();// 邻接表添加反向边g.get(v).add(u);}// 从每个节点进行DFSfor (int i = n; i >= 1; i--) {dfs(i, i);}// 输出结果for (int i = 1; i <= n; i++) {System.out.print(num[i] + " ");}System.out.println();}private static void dfs(int x, int d) {if (num[x] != 0) return; // 如果访问过,则返回num[x] = d; // 记录从x出发到达的最大节点编号for (int neighbor : g.get(x)) {dfs(neighbor, d);}}
}

P1113 杂务 

解题思路(拓扑排序)

1. 问题建模

  • 每个杂务可以看作一个节点,依赖关系可以看作有向边。这是一个有向图的问题。
  • 输入中每个任务的完成时间和依赖的任务形成了图的结构。

2. 使用拓扑排序

  • 由于任务之间存在依赖关系,我们需要确保在计算一个任务的完成时间时,其所有依赖的任务都已经完成。
  • 我们可以使用拓扑排序的方法来处理这个问题。入度(依赖的任务数量)为0的任务可以立即开始执行。
import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int n = input.nextInt(); // 任务数量int[] index = new int[n + 1]; // 入度数组int[] time = new int[n + 1]; // 完成时间数组int[] lim = new int[n + 1]; // 每个任务的时间List<List<Integer>> edge = new ArrayList<>(n + 1); // 邻接表// 初始化邻接表for (int i = 0; i <= n; i++) {edge.add(new ArrayList<>());}// 读取任务信息for (int i = 1; i <= n; i++) {int x = input.nextInt(); // 任务编号lim[x] = input.nextInt(); // 任务所需时间while (true) {int y = input.nextInt(); // 读取依赖的任务if (y == 0) break; // 结束读取依赖edge.get(y).add(x); // 记录依赖关系index[x]++; // 更新入度}}// 队列用于拓扑排序Queue<Integer> q = new LinkedList<>();// 将入度为0的任务入队for (int i = 1; i <= n; i++) {if (index[i] == 0) {q.add(i);time[i] = lim[i]; // 初始化完成时间}}// 进行拓扑排序while (!q.isEmpty()) {int rhs = q.poll(); // 取出队首任务// 遍历依赖该任务的所有任务for (int u : edge.get(rhs)) {index[u]--; // 入度减1// 如果入度为0,则入队if (index[u] == 0) {q.add(u);}// 更新任务的完成时间time[u] = Math.max(time[u], time[rhs] + lim[u]);}}// 统计所有任务完成时间的最大值int ans = 0;for (int i = 1; i <= n; i++) {ans = Math.max(ans, time[i]);}// 输出结果System.out.println(ans);}
}

 解题思路(动态规划)

我们可以使用动态规划的方法来计算每个任务的完成时间。每个任务的完成时间依赖于它所有依赖的任务的完成时间。

  • 输入处理

    • 读取任务的数量 n,并初始化完成时间数组 ans 和最大完成时间 maxAns
    • 逐个读取每个任务的编号、所需时间以及依赖的任务,直到读取到 0 为止。
  • 计算完成时间

    • 对于每个任务,首先记录其依赖任务的最大完成时间 tmp
    • 将当前任务的完成时间 ans[i] 设置为 tmp 加上当前任务所需的时间。
    • 更新 maxAns 为当前任务的完成时间和已有的最大完成时间中的较大者。
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);int n = input.nextInt(); // 任务数量int[] ans = new int[10005]; // 完成时间数组int maxAns = 0; // 最大完成时间// 读取每个任务的信息for (int i = 1; i <= n; i++) {int taskId = input.nextInt(); // 任务编号int l = input.nextInt(); // 任务所需时间int tmp = 0; // 用于记录依赖任务的最大完成时间// 读取依赖项while (true) {int t = input.nextInt(); // 读取依赖的任务if (t == 0) break; // 结束读取依赖tmp = Math.max(ans[t], tmp); // 更新最大依赖完成时间}ans[taskId] = tmp + l; // 当前任务的完成时间maxAns = Math.max(ans[taskId], maxAns); // 更新最大完成时间}// 输出结果System.out.println(maxAns);}
}

P4017 最大食物链计数

解题思路

  1. 问题分析:题目要求计算从生产者(入度为0的节点)到顶级消费者(出度为0的节点)的所有路径数目之和。这类问题可以通过拓扑排序结合动态规划(DP)来解决。

  2. 图构建:使用邻接表存储每个节点的后继节点(即该节点被哪些生物捕食),并统计每个节点的入度和出度。

  3. 拓扑排序:初始化所有生产者节点的路径数为1,然后按照拓扑顺序处理每个节点,将其路径数累加到其后继节点的路径数中。

  4. 动态规划:每个节点的路径数表示以该节点为终点的路径数目。在拓扑排序过程中,逐步更新每个节点的路径数。

  5. 结果计算:遍历所有出度为0的节点(顶级消费者),将其路径数累加得到最终结果,并取模处理。

import java.io.*;
import java.util.*;public class Main {static final int MOD = 80112002; // 定义取模常量public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String[] parts = br.readLine().split(" ");int n = Integer.parseInt(parts[0]); // 节点数int m = Integer.parseInt(parts[1]); // 边数// 邻接表表示图List<Integer>[] adj = new ArrayList[n + 1];for (int i = 1; i <= n; i++) {adj[i] = new ArrayList<>();}int[] inDegree = new int[n + 1]; // 入度数组int[] outDegree = new int[n + 1]; // 出度数组// 读取边信息并构建图for (int i = 0; i < m; i++) {parts = br.readLine().split(" ");int a = Integer.parseInt(parts[0]); // 起点int b = Integer.parseInt(parts[1]); // 终点adj[a].add(b); // 添加边 a -> binDegree[b]++; // 增加 b 的入度outDegree[a]++; // 增加 a 的出度}int[] dp = new int[n + 1]; // dp[i] 表示从某个生产者到节点 i 的路径数Queue<Integer> queue = new LinkedList<>(); // 队列用于拓扑排序// 初始化生产者(入度为 0 的节点)for (int i = 1; i <= n; i++) {if (inDegree[i] == 0) {dp[i] = 1; // 生产者的路径数初始化为 1queue.offer(i); // 将生产者加入队列}}// 拓扑排序处理while (!queue.isEmpty()) {int u = queue.poll(); // 取出队首节点for (int v : adj[u]) { // 遍历 u 的所有邻接节点dp[v] = (dp[v] + dp[u]) % MOD; // 更新路径数,取模防止溢出if (--inDegree[v] == 0) { // 如果 v 的入度变为 0,加入队列queue.offer(v);}}}// 计算所有顶级消费者的路径总和int sum = 0;for (int i = 1; i <= n; i++) {if (outDegree[i] == 0) { // 顶级消费者(出度为 0 的节点)sum = (sum + dp[i]) % MOD; // 累加路径数,取模防止溢出}}System.out.print(sum); // 输出结果}
}

P1807 最长路

解题思路

  • 问题分析:我们需要求解从顶点1到顶点n的最长路径。由于这是一个有向无环图(DAG),可以使用拓扑排序来简化求解最长路径的问题。

  • 拓扑排序与动态规划

    • 首先,构建图的邻接表并计算每个节点的入度。
    • 使用拓扑排序从起点开始遍历图,确保每个节点只会在其前驱节点都处理完后才被处理,从而避免环。
    • 利用动态规划,设dist[i]表示从起点1到节点i的最长路径。初始化dist[1] = 0,其他节点的dist初始化为负无穷。
    • 在遍历每条边u -> v时,若dist[u] + w > dist[v],则更新dist[v] = dist[u] + w
  • 结果输出

    • 最后,若dist[n]仍为负无穷,表示1无法到达n,输出-1
    • 否则,输出dist[n]
import java.util.*;public class Main {static final int INF = Integer.MIN_VALUE;static int[] dist, inDegree;static List<int[]>[] graph;static int n, m;public static void main(String[] args) {Scanner input = new Scanner(System.in);n = input.nextInt();m = input.nextInt();dist = new int[n + 1];Arrays.fill(dist, INF);  // 初始化距离dist[1] = 0;  // 起点的距离为0inDegree = new int[n + 1];graph = new ArrayList[n + 1];for (int i = 1; i <= n; i++) {graph[i] = new ArrayList<>();}for (int i = 0; i < m; i++) {int u = input.nextInt();int v = input.nextInt();int w = input.nextInt();graph[u].add(new int[]{v, w});inDegree[v]++;}if (topoSortAndLongestPath()) {System.out.println(dist[n]);} else {System.out.println(-1);  // 无法到达n}}static boolean topoSortAndLongestPath() {Queue<Integer> queue = new LinkedList<>();// 初始化拓扑排序队列for (int i = 1; i <= n; i++) {if (inDegree[i] == 0) {queue.offer(i);}}int visitedCount = 0;while (!queue.isEmpty()) {int u = queue.poll();visitedCount++;for (int[] edge : graph[u]) {int v = edge[0], w = edge[1];// 更新最长路径if (dist[u] != INF) {dist[v] = Math.max(dist[v], dist[u] + w);}// 更新入度并检查是否可以入队if (--inDegree[v] == 0) {queue.offer(v);}}}return visitedCount == n && dist[n] != INF;}
}

P1127 词链

解题思路

  • 输入与初始化

    • 首先读取字符串数量 n 和每个字符串。利用 ind 数组记录每个字符作为字符串结束字符的数量,利用 rnd 数组记录每个字符作为字符串开始字符的数量。
  • 邻接表构建

    • 对字符串进行字典序排序。通过两层循环检查每个字符串对,如果一个字符串的最后一个字符与另一个字符串的第一个字符相同,则在邻接表中记录这一边。
  • 欧拉路径搜索

    • 欧拉路径要求图的入度和出度特定匹配。通常,起点的出度应大于入度一,而其他节点的入度与出度应相等。因此,使用 indrnd 数组来找到合适的起点。
    • 使用 DFS 方法搜索所有可能的路径。如果找到了包含所有字符串的路径,则输出结果并结束程序。
  • 处理边界条件

    • 如果没有找到任何有效路径,程序输出 "***" 表示无法形成有效的欧拉路径。
import java.util.*;public class Main {static int n; // 字符串数量static String[] a = new String[1001]; // 存储输入的字符串static List<Integer>[] e = new ArrayList[1001]; // 邻接表,用于存储边static int[] ind = new int[1001]; // 入度数组,记录每个字符作为结束字符的字符串数量static int[] outd = new int[1001]; // 出度数组,记录每个字符作为开始字符的字符串数量static boolean[] used = new boolean[1001]; // 标记字符串是否已经使用// 深度优先搜索函数static void dfs(int s, String curr, int count) {// 当找到一个完整的路径时if (count == n) {System.out.println(curr.substring(0, curr.length() - 1)); // 去掉最后的点System.exit(0); // 找到答案后退出程序}// 遍历当前字符串可以连接的下一个字符串for (int next : e[s]) {if (!used[next]) { // 如果下一个字符串未被使用used[next] = true; // 标记为已使用// 递归调用,继续深度优先搜索dfs(next, curr + a[next] + ".", count + 1);used[next] = false; // 回溯,取消使用标记}}}public static void main(String[] args) {Scanner input = new Scanner(System.in);n = input.nextInt(); // 读取字符串数量// 读取字符串并初始化数据结构for (int i = 1; i <= n; ++i) {a[i] = input.next(); // 存储字符串ind[a[i].charAt(0)]++; // 更新入度outd[a[i].charAt(a[i].length() - 1)]++; // 更新出度e[i] = new ArrayList<>(); // 初始化邻接表}Arrays.sort(a, 1, n + 1); // 按字典序排序字符串// 建立邻接关系for (int i = 1; i <= n; ++i) {for (int j = 1; j <= n; ++j) {// 如果当前字符串的最后一个字符与下一个字符串的第一个字符相同if (i != j && a[i].charAt(a[i].length() - 1) == a[j].charAt(0)) {e[i].add(j); // 记录边}}}// 尝试以每个合适的字符串作为起始点for (int i = 1; i <= n; ++i) {if (ind[a[i].charAt(0)] == outd[a[i].charAt(0)] + 1) {used[i] = true; // 标记当前字符串为已使用dfs(i, a[i] + ".", 1); // 从当前字符串开始 DFSused[i] = false; // 回溯}}// 如果没有找到合适的起始点,默认从第一个字符串开始used[1] = true;dfs(1, a[1] + ".", 1); // 从第一个字符串开始 DFSused[1] = false; // 回溯// 如果没有找到路径,输出 "***"System.out.println("***");}
}

P2853 [USACO06DEC] Cow Picnic S

解题思路

  • 构建图

    • 使用邻接表表示有向图,其中每个牧场指向可以到达的其他牧场。
    • 反向图也很重要,用于检查某个牧场是否可以被所有奶牛到达。
  • BFS 遍历

    • 对每头奶牛使用 BFS 遍历,从奶牛所在的牧场出发,找出所有可达的牧场,记录这些牧场。
    • 使用一个集合来存储所有可达的牧场。
  • 反向 BFS 检查

    • 对于每个在可达集合中的牧场,使用反向 BFS 来检查从该牧场能否到达所有奶牛的牧场。
    • 如果从当前牧场出发,可以访问到所有奶牛的起始牧场,则该牧场是可供聚餐的地点。
  • 结果统计

    • 统计所有能被所有奶牛到达的牧场数量。
import java.util.*;public class Main {public static void main(String[] args) {Scanner input = new Scanner(System.in);// 读取输入值int K = input.nextInt(); // 奶牛数量int N = input.nextInt(); // 牧场数量int M = input.nextInt(); // 路径数量int[] cowPositions = new int[K]; // 存储每头奶牛所在的牧场for (int i = 0; i < K; i++) {cowPositions[i] = input.nextInt();}List<List<Integer>> graph = new ArrayList<>(); // 牧场的有向图List<List<Integer>> reverseGraph = new ArrayList<>(); // 牧场的反向图for (int i = 0; i <= N; i++) {graph.add(new ArrayList<>());reverseGraph.add(new ArrayList<>());}// 读取有向路径并构建图for (int i = 0; i < M; i++) {int A = input.nextInt();int B = input.nextInt();graph.get(A).add(B); // A 到 B 的有向边reverseGraph.get(B).add(A); // 反向边}// 步骤 1:找出所有奶牛可以到达的牧场Set<Integer> reachableFromCows = new HashSet<>(); // 可达的牧场集合boolean[] visited = new boolean[N + 1]; // 访问标记// 对每头奶牛进行 BFS,找到可达的牧场for (int cow : cowPositions) {if (!visited[cow]) {bfs(cow, graph, visited, reachableFromCows);}}// 步骤 2:检查哪些可达牧场能够被所有奶牛到达int count = 0; // 可供进食的牧场计数for (int pasture : reachableFromCows) {visited = new boolean[N + 1]; // 重置访问标记int reachableCount = 0; // 记录可以到达的奶牛数量// 反向 BFS,检查当前牧场是否可以到达所有奶牛的牧场bfsReverse(pasture, reverseGraph, visited);// 统计可以到达的奶牛数量for (int cow : cowPositions) {if (visited[cow]) {reachableCount++;}}// 如果当前牧场可以到达所有奶牛,计数加一if (reachableCount == K) {count++;}}// 输出结果System.out.println(count);}// BFS 方法,找出从起始牧场可达的所有牧场private static void bfs(int start, List<List<Integer>> graph, boolean[] visited, Set<Integer> reachable) {Queue<Integer> queue = new LinkedList<>();queue.add(start);visited[start] = true;while (!queue.isEmpty()) {int current = queue.poll(); // 取出队首reachable.add(current); // 记录可达牧场// 遍历相邻牧场for (int neighbor : graph.get(current)) {if (!visited[neighbor]) {visited[neighbor] = true; // 标记为已访问queue.add(neighbor); // 入队}}}}// 反向 BFS 方法,找出能到达当前牧场的奶牛数量private static void bfsReverse(int start, List<List<Integer>> reverseGraph, boolean[] visited) {Queue<Integer> queue = new LinkedList<>();queue.add(start);visited[start] = true;while (!queue.isEmpty()) {int current = queue.poll(); // 取出队首// 遍历反向相邻牧场for (int neighbor : reverseGraph.get(current)) {if (!visited[neighbor]) {visited[neighbor] = true; // 标记为已访问queue.add(neighbor); // 入队}}}}
}

P1363 幻象迷宫

解题思路

解题代码修改自https://www.luogu.com.cn/record/206017952。

1. 输入处理

  • 迷宫大小:通过输入读取迷宫的行数 n 和列数 m。
  • 迷宫地图:读取迷宫的每一行数据,存储到二维字符数组 s 中。
  • 起点查找:遍历迷宫,找到起点 'S' 的位置 (startX, startY)

2. 广度优先搜索 (BFS)

  • 队列初始化:使用队列 Queue<Point> 存储当前访问的点,起点首先入队。
  • 状态标记:使用二维数组 book 记录每个位置的访问状态,状态通过自定义哈希函数 f(x, y) 计算。
  • 方向扩展:定义四个方向的移动向量 ne,分别表示右、下、左、上。
BFS 的核心逻辑:
  1. 从队列中取出当前点 (x, y)
  2. 遍历四个方向,计算新位置 (nx, ny)
  3. 无限地图映射:将无限地图的坐标 (nx, ny) 映射到有限范围 (tx, ty)
  4. 状态判断
    • 如果新位置是墙壁 '#',跳过。
    • 如果新位置未被访问过,标记状态并加入队列。
    • 如果新位置已被访问过,但状态不同,说明存在循环路径,返回 true
  5. 如果队列为空且未发现循环路径,返回 false

3. 自定义哈希函数

  • 函数 f(x, y) 用于计算每个位置的状态值,确保在无限地图中不同的坐标映射到有限范围时仍能区分状态。
  • 公式:

    ((x + n * 4) / n) * 131 + ((y + m * 4) / m) * 13

    • (x + n * 4) / n 和 (y + m * 4) / m 确保坐标映射到有限范围。
    • 乘以不同的常数(131 和 13)避免哈希冲突。

4. 无限地图映射

  • 迷宫是无限重复的,通过以下公式将无限坐标 (nx, ny) 映射到有限范围 (tx, ty)

    tx = (nx + n * 10) % n;

    ty = (ny + m * 10) % m;

    • + n * 10 和 + m * 10 确保坐标为正数。
    • % n 和 % m 将坐标限制在迷宫的行列范围内。
import java.util.*;public class Main {// 定义四个方向的移动向量:右、下、左、上static int[][] ne = {{0,1}, {1,0}, {0,-1}, {-1,0}};static int[][] book; // 记录每个位置的状态static char[][] s;   // 存储迷宫地图static int n, m;     // 迷宫的行数和列数// 定义一个点的类,用于存储坐标static class Point {int x, y;Point(int x, int y) {this.x = x;this.y = y;}}// 自定义哈希函数,用于标记每个位置的状态static int f(int x, int y) {return ((x + n * 4) / n) * 131 + ((y + m * 4) / m) * 13;}// 广度优先搜索 (BFS) 判断是否存在循环路径static boolean bfs(int x, int y) {Queue<Point> q = new LinkedList<>(); // 队列用于存储当前访问的点q.offer(new Point(x, y)); // 将起点加入队列book[x][y] = f(x, y); // 标记起点的状态while (!q.isEmpty()) {Point u = q.poll(); // 取出队首元素for (int[] dir : ne) { // 遍历四个方向int nx = u.x + dir[0]; // 新的 x 坐标int ny = u.y + dir[1]; // 新的 y 坐标// 处理无限地图的坐标映射int tx = (nx + n * 10) % n; // 映射到迷宫内的行int ty = (ny + m * 10) % m; // 映射到迷宫内的列int t = f(nx, ny); // 计算新的状态// 如果当前位置是墙壁,跳过if (s[tx][ty] == '#') continue;// 如果当前位置未被访问过if (book[tx][ty] == 0) {book[tx][ty] = t; // 标记状态q.offer(new Point(nx, ny)); // 加入队列}// 如果当前位置被访问过,但状态不同,说明存在循环else if (book[tx][ty] != t) {return true;}}}return false; // 如果搜索结束没有发现循环,返回 false}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()) {String temp = scanner.nextLine().trim(); // 读取迷宫的大小if (temp.isEmpty()) break; // 输入结束条件n = Integer.parseInt(temp.split(" ")[0]); // 行数m = Integer.parseInt(temp.split(" ")[1]); // 列数s = new char[n][m]; // 初始化迷宫地图book = new int[n][m]; // 初始化标记数组// 读取地图数据for (int i = 0; i < n; i++) {String l = scanner.nextLine().trim();while (l.isEmpty()) { // 跳过空行l = scanner.nextLine().trim();}s[i] = l.toCharArray(); // 将每行数据存入地图}// 查找起点 'S'int startX = 0, startY = 0;outerloop:for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (s[i][j] == 'S') { // 找到起点startX = i;startY = j;break outerloop; // 跳出双重循环}}}// 输出结果:是否存在循环路径System.out.println(bfs(startX, startY) ? "Yes" : "No");}scanner.close();}
}

P1347 排序

解题思路

  • 输入处理

    • 首先读取节点数量 n 和关系数量 m
    • 根据输入的边(关系),更新邻接表和入度数组,建立图的结构。
  • 拓扑排序逻辑

    • 通过 topo(int r) 函数进行拓扑排序。该函数尝试构造一个拓扑排序的结果。
    • 维护一个临时入度数组 t,并将入度为0的节点入栈(代表可以先访问的节点)。
    • 在处理每个节点时,如果发现有多个节点可以入栈(即有多个入度为0的节点),则标记 finishedfalse,表示当前状态下可能有多种排序方式。
    • 每当处理完一个节点后,更新其相邻节点的入度,并检查这些相邻节点是否可以入栈。
    • 如果最终排序结果中的节点数量少于总节点数量,表示图中存在环,返回 false
  • 判断和输出结果

    • 在每次添加新关系后,都执行一次拓扑排序,如果发现不一致(如存在环),则输出错误信息并终止。
    • 如果成功完成排序且找到了有效的排序顺序,则打印排序结果。
    • 如果在处理完所有关系后仍未找到有效排序,则输出“无法确定排序顺序”。
import java.util.*;public class Main {static final int MAXN = 30; // 最大节点数static int n, m; // n 为节点数量,m 为关系数量static List<Integer>[] e = new ArrayList[MAXN]; // 邻接表static int[] degree = new int[MAXN]; // 入度数组static int[] a = new int[MAXN]; // 排序结果static Stack<Integer> s = new Stack<>(); // 用于拓扑排序的栈static boolean[] vis = new boolean[MAXN]; // 访问标记static int mrk = 0; // 标记是否成功排序// 拓扑排序函数,返回值为真表示成功static boolean topo(int r) {int sz = 0; // 记录排序结果的大小boolean finished = true; // 标记是否存在多个入度为0的节点int[] t = new int[MAXN]; // 用于临时存储入度// 初始化入度和入度为0的节点for (int i = 0; i < n; i++) {t[i] = degree[i];if (t[i] == 0) {s.push(i);vis[i] = true; // 标记为已访问}}while (!s.isEmpty()) {if (s.size() > 1) finished = false; // 存在多个入度为0的节点int k = s.pop(); // 取出栈顶元素a[sz++] = k; // 记录排序结果// 更新邻接节点的入度for (int v : e[k]) {t[v]--;}// 查找新的入度为0的节点for (int i = 0; i < n; i++) {if (t[i] == 0 && !vis[i]) {s.push(i);vis[i] = true; // 标记为已访问}}}if (sz < n) return false; // 如果排序结果小于节点数,表示有循环if (finished && mrk == 0) mrk = r; // 更新成功标记return true;}public static void main(String[] args) {Scanner input = new Scanner(System.in);n = input.nextInt(); // 输入节点数量m = input.nextInt(); // 输入关系数量// 初始化邻接表for (int i = 0; i < MAXN; i++) {e[i] = new ArrayList<>();}// 输入边并构建图for (int i = 1; i <= m; i++) {String c = input.next(); // 读取边int x = c.charAt(0) - 'A'; // 起点int y = c.charAt(2) - 'A'; // 终点e[x].add(y); // 添加边degree[y]++; // 更新入度if (mrk > 0) {break; // 如果已经成功排序,跳过后续输入(记录成环的特殊情况)}// 执行拓扑排序if (!topo(i)) {System.out.println("Inconsistency found after " + i + " relations.");return; // 如果存在矛盾,终止程序}Arrays.fill(vis, false); // 重置访问标记}// 输出排序结果if (mrk > 0) {System.out.print("Sorted sequence determined after " + mrk + " relations: ");for (int j = 0; j < n; j++) {System.out.print((char)(a[j] + 'A')); // 输出排序的字母}System.out.println(".");} else {System.out.println("Sorted sequence cannot be determined.");}}
}

P1983 [NOIP2013 普及组] 车站分级

解题思路

  • 图的表示

    • 使用 Node 类表示图中的每个节点。每个节点包含:
      • level: 表示该节点的层级,初始值为 1。
      • in_d: 表示该节点的入度(指向该节点的边的数量)。
      • adj: 使用 BitSet 来存储该节点的邻接节点(即哪些节点指向它)。
  • 输入处理

    • 使用 StreamTokenizer 进行高效的输入处理,以便快速读取大量数据。
    • 首先读取节点数 N,然后读取边的数目 M
  • 构建图

    • 对于每条边,首先记录每个相关节点的入度。
    • 遍历节点范围,将未被访问的节点标记,并建立它们与当前边的邻接关系。
  • 拓扑排序

    • 使用队列(ArrayDeque)来存储入度为 0 的节点。
    • 在遍历队列时,处理当前节点的所有邻接节点,减少它们的入度。如果某个邻接节点的入度变为 0,则将其加入队列。
    • 同时更新每个邻接节点的层级,确保每个节点的层级总是反映其在图中的位置。
  • 计算最大层级

    • 遍历所有节点,找到最大层级值,输出结果。
import java.io.*;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.BitSet;public class Main {// 定义节点类,保存每个节点的深度和入度private static class Node {short level;  // 当前节点的层级short in_d = 0;  // 该节点的入度BitSet adj;  // 邻接表,用 BitSet 存储连接的节点Node() {level = 1;  // 默认层级为 1}}public static void main(String[] args) throws IOException {// 使用 StreamTokenizer 进行高效的输入处理StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));// 读取节点数量 Nin.nextToken();int N = (int) in.nval;// 创建节点数组Node[] nodes = new Node[N + 1];boolean[] vis = new boolean[N + 1];  // 记录是否访问过short[] st = new short[N + 1];  // 存储临时数据// 初始化节点for (int i = 1; i < N + 1; i++) nodes[i] = new Node();// 读取边的数量 Min.nextToken();int M = (int) in.nval;// 处理每条边for (int i = 0; i < M; i++) {in.nextToken();  // 读取当前边的节点数st[0] = (short) in.nval;  // st[0] 存储当前边的节点数// 读取当前边的所有节点for (int j = 1; j <= st[0]; j++) {in.nextToken();st[j] = (short) in.nval;  // 将节点存入 st 数组vis[st[j]] = true;  // 标记节点为已访问}// 遍历节点范围,设置入度和邻接关系for (int j = st[1]; j <= st[st[0]]; j++) {if (vis[j]) continue;  // 如果节点已经访问过,跳过// 初始化邻接表if (nodes[j].adj == null) nodes[j].adj = new BitSet();// 更新入度和邻接关系for (int k = 1; k <= st[0]; k++) {if (!nodes[j].adj.get(st[k])) {  // 如果未连接nodes[st[k]].in_d++;  // 增加入度nodes[j].adj.set(st[k]);  // 记录邻接关系}}}Arrays.fill(vis, false);  // 清空访问标记}// 使用队列进行拓扑排序ArrayDeque<Node> deque = new ArrayDeque<>();// 将入度为 0 的节点加入队列for (int i = 1; i <= N; i++) if (nodes[i].in_d == 0) deque.add(nodes[i]);// 拓扑排序过程while (!deque.isEmpty()) {Node cur = deque.poll();  // 取出队首节点if (cur.adj == null) continue;  // 如果没有邻接节点,跳过// 遍历当前节点的所有邻接节点int i = cur.adj.nextSetBit(0);while (i >= 0) {// 减少邻接节点的入度if (--nodes[i].in_d == 0) {deque.add(nodes[i]);  // 如果入度为 0,则加入队列// 更新邻接节点的层级if (cur.level + 1 > nodes[i].level) nodes[i].level = (short) (cur.level + 1);}i = cur.adj.nextSetBit(i + 1);  // 获取下一个邻接节点}}// 计算最大层级int ans = 0;for (int i = 1; i <= N; i++) ans = Math.max(ans, nodes[i].level);// 输出结果System.out.println(ans);}
}

http://www.dtcms.com/wzjs/209982.html

相关文章:

  • vue做门户网站用什么uiseo就业哪家好
  • 合工大网站建设试卷灰色关键词排名代发
  • 如何做 行业社交类网站千锋教育课程
  • 济南建站优化百度账号个人中心
  • 免费模板app下载seo关键词排名优化哪家好
  • seo短视频网页入口引流网站推荐成都seo学徒
  • 建网站用什么服务器好优化大师优化项目有
  • 郑州富士康招聘网官网成都百度提升优化
  • 网站主页跳转indexseo网络营销推广排名
  • 做游戏的php网站有哪些app接入广告变现
  • 网站开发常用形状微信公众号运营
  • 网站备案 子域名建设网站制作公司
  • 香港做网站什么费用优化的意思
  • 做装饰公司网站汉川seo推广
  • 免费的网站生成app口碑营销推广
  • 做公益网站需要什么资质公司网络营销策略
  • 广告设计公司营业执照win10优化大师
  • 陕西疫情最新数据消息seo优化专员工作内容
  • 安陆 网站建设排名优化公司
  • 政府培训如何做网站推广windows优化大师官方免费下载
  • 湛江网站开发企业宣传文案
  • 做多站发布信息的网站seo网站推广是什么意思
  • 网站推广 经典案例济南百度推广优化
  • 建设农家书屋官方网站软文发布平台与板块
  • 什么网站可以做代购seo专员的工作内容
  • 网站美工外包公司石家庄新闻最新消息
  • 网站导航排版布局百度快照收录入口
  • 网站建设视频想做网络推广如何去做
  • 跟公司产品做网站国内重大新闻10条
  • 做网站要用到哪些架包怎样免费给自己的公司做网站