解题思路

这是一道拓扑排序问题:

  1. 每道菜品的品尝顺序可以看作有向图中的节点
  2. "前置菜肴"的要求可以看作有向边
  3. 如果存在合法的品尝顺序,则图中不存在环
  4. 使用拓扑排序算法可以得到一个合法的品尝顺序

解题步骤:

  1. 构建邻接表表示图结构
  2. 计算每个节点的入度
  3. 将入度为0的节点加入队列
  4. 不断取出队首节点,减少其相邻节点的入度
  5. 如果最终访问的节点数小于总节点数,说明存在环,返回None

代码

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

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    
    // 构建图和入度数组
    vector<vector<int>> graph(n);
    vector<int> indegree(n, 0);
    for(int i = 0; i < m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        graph[v].push_back(u);  // v必须在u之前吃
        indegree[u]++;
    }
    
    // 拓扑排序
    queue<int> q;
    for(int i = 0; i < n; i++) {
        if(indegree[i] == 0) q.push(i);
    }
    
    vector<int> ans;
    while(!q.empty()) {
        int curr = q.front();
        q.pop();
        ans.push_back(curr);
        
        for(int next : graph[curr]) {
            if(--indegree[next] == 0) {
                q.push(next);
            }
        }
    }
    
    // 输出结果
    if(ans.size() < n) {
        printf("None\n");
    } else {
        for(int i = 0; i < n - 1; i++) {
            printf("%d,", ans[i]);
        }
        printf("%d\n", ans.back());
    }
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        
        // 构建图和入度数组
        List<List<Integer>> graph = new ArrayList<>();
        for(int i = 0; i < n; i++) {
            graph.add(new ArrayList<>());
        }
        int[] indegree = new int[n];
        
        for(int i = 0; i < m; i++) {
            int u = sc.nextInt();
            int v = sc.nextInt();
            graph.get(v).add(u);
            indegree[u]++;
        }
        
        // 拓扑排序
        Queue<Integer> q = new LinkedList<>();
        for(int i = 0; i < n; i++) {
            if(indegree[i] == 0) q.offer(i);
        }
        
        List<Integer> ans = new ArrayList<>();
        while(!q.isEmpty()) {
            int curr = q.poll();
            ans.add(curr);
            
            for(int next : graph.get(curr)) {
                if(--indegree[next] == 0) {
                    q.offer(next);
                }
            }
        }
        
        // 输出结果
        if(ans.size() < n) {
            System.out.println("None");
        } else {
            StringBuilder sb = new StringBuilder();
            for(int i = 0; i < ans.size() - 1; i++) {
                sb.append(ans.get(i)).append(",");
            }
            sb.append(ans.get(ans.size() - 1));
            System.out.println(sb.toString());
        }
    }
}
from collections import defaultdict, deque

def solve(n, m, prerequisites):
    # 构建图和入度数组
    graph = defaultdict(list)
    indegree = [0] * n
    
    for u, v in prerequisites:
        graph[v].append(u)
        indegree[u] += 1
    
    # 拓扑排序
    q = deque([i for i in range(n) if indegree[i] == 0])
    ans = []
    
    while q:
        curr = q.popleft()
        ans.append(curr)
        
        for next_node in graph[curr]:
            indegree[next_node] -= 1
            if indegree[next_node] == 0:
                q.append(next_node)
    
    # 返回结果
    return None if len(ans) < n else ','.join(map(str, ans))

n, m = map(int, input().split())
prerequisites = []
for _ in range(m):
    u, v = map(int, input().split())
    prerequisites.append((u, v))

result = solve(n, m, prerequisites)
print(result if result is not None else "None")

算法及复杂度

  • 算法:拓扑排序(BFS实现)
  • 时间复杂度: - 其中 是节点数, 是边数
  • 空间复杂度: - 需要存储图结构和队列