1 solutions
-
0
题目大意
给定若干条指令(最多 100 条),每条指令可能依赖于其他指令。指令之间的依赖关系用 PRO-CON 关系表示,其中 PRO 表示生产者指令,CON 表示消费者指令,依赖的延迟时间(latency)也随之给出。任务是计算每条指令的优先级,并根据优先级进行排序
题目思路
这道题主要涉及 拓扑排序 和 动态规划 的结合应用。具体步骤如下:
1.建立图模型:
将每条指令看作图中的一个节点。 PRO-CON 关系看作有向边,从 PRO 指令指向 CON 指令。 每条边带有一个权重,表示延时。
2.拓扑排序:
由于指令依赖关系形成了一个有向无环图(DAG),可以对图进行拓扑排序。 拓扑排序的目的是确保所有指令按照依赖关系的顺序执行。
3.动态规划计算优先级:
初始化每条指令的 优先级 为 0。 按照拓扑排序的顺序处理每个节点: 对于每个 CON 指令,根据其所有 PRO 指令的 优先级 和延时,更新其 优先级 为所有可能值中的最大值。 具体地,对于每条边 u -> v,更新 PRIORITY(v) = max(PRIORITY(v), PRIORITY(u) + L)。 4.排序指令:
根据计算得到的 优先级 对指令进行排序。 优先级高的指令排在前面。 如果优先级相同,则编号小的指令排在前面。
整道题可以说是DAG动态规划的板子题,也是拓扑排序的板子题。不理解的话可以去搜索一下复习一下。
代码说明
代码整体流程
1.输入读取:
从标准输入读取指令的数量 n(总指令数)和关系的数量 m(依赖关系数)。接着,读取接下来的 m 行,每行的格式为 (u, v, latency),表示指令 u 依赖于指令 v,并且有一定的延迟时间。
2.初始化变量:
创建一个邻接表或动态数组 edge,用于存储每条指令的依赖关系。初始化一个数组 ans,用于记录每条指令的优先级和对应的编号。还需要一个数组 in,用于记录每个指令的入度,表示有多少条指令依赖于该指令。
3.构建图:
遍历输入的依赖关系,更新邻接表,记录每条指令的消费者和对应的延迟。同时更新入度数组,记录每条指令被多少其他指令依赖。
4.拓扑排序:
使用队列实现拓扑排序,将所有入度为 0 的指令入队,并初始化这些指令的优先级为 0。接下来,进行广度优先搜索(BFS),不断从队列中取出指令,更新其消费者的优先级,并减少消费者的入度。
5.优先级计算:
在处理每条指令时,根据依赖关系和延迟时间更新消费者的优先级。对于每个消费者,优先级的计算规则是:优先级(v) = 最大值(优先级(u) + 延迟)。在这个过程中,维护优先级数组,记录每条指令的最大优先级和对应的编号。
6.排序结果:
使用排序算法对优先级数组进行排序。首先按优先级从高到低排序,如果优先级相同,则按指令编号升序排序。
7.输出结果:
遍历排序后的优先级数组,输出每条指令的编号(根据需要调整索引),形成最终的排序结果。
代码
Java代码
import java.util.*; public class Main { static class Edge{//记录边 public int to; public int val; Edge(int a, int b){ to = a; val = b; } Edge(){} } static class Value{//记录我们最后的答案统计 public int val1 = 0; public int val2 = 0; Value(int a, int b){ val1 = a; val2 = b; } Value(){val1 = val2 = 0;} } public static void main(String[] args) { Scanner input = new Scanner(System.in); int n = input.nextInt(); int m = input.nextInt(); //二维数组用于存储边,第一位是固定数组,第二维是动态数组 ArrayList<Edge>[] edge = new ArrayList[n]; Value[] ans = new Value[n];//记录我们的答案,最后需要排序 int[] in = new int[n];//拓扑排序的要点,记录一个点的入度 for(int i = 0; i < n; i++){//初始化 edge[i] = new ArrayList<Edge>(); ans[i] = new Value(); } for (int i = 1; i <= m; i++){ int u = input.nextInt(); int v = input.nextInt(); int val = input.nextInt(); u--; v--; edge[v].add(new Edge(u, val));//加边 in[u]++;//加度 } Queue<Integer> q = new LinkedList<Integer>();//拓扑排序bfs版,需要队列 for(int i = 0; i < n; i++){ if(in[i] == 0){ q.offer(i);//度数为0的直接压进队列 ans[i] = new Value(0, i);//答案数记为(0,i),0是他的latency,i是编号 } } while(!q.isEmpty()){ int u = q.poll();//队列非空的时候不断取点 for(int i = 0; i < edge[u].size(); i++){ int v = edge[u].get(i).to; //更新答案,DAG动态规划的核心步骤 ans[v].val1 = Math.max(ans[v].val1, ans[u].val1 + edge[u].get(i).val); ans[v].val2 = v; in[v]--;//如果度数为0,就压进队列,也是拓扑排序的核心 if(in[v] == 0)q.offer(v); } } Arrays.sort(ans, new Comparator<Value>() {//排序 @Override public int compare(Value o1, Value o2) { if(o1.val1 == o2.val1)return o1.val2 - o2.val2; else return o2.val1 - o1.val1; } }); for(int i = 0; i < n; i++){//输出答案 System.out.print(ans[i].val2 + 1); if(i != n - 1) System.out.print(" "); } } }
C++代码
#include <bits/stdc++.h> using namespace std; struct Edge { //记录边 int to; int val; Edge(int a, int b) { to = a; val = b; } Edge() {} }; struct Value { //记录我们最后的答案统计 int val1 = 0; int val2 = 0; Value(int a, int b) { val1 = a; val2 = b; } Value() {val1 = val2 = 0;} bool operator<(Value b) //排序 { return val1!=b.val1?val1>b.val1:val2<b.val2; } }; int in[505]; Value ans[505]; int main() { int n, m; cin >> n >> m; vector<Edge>edge[505]; for (int i = 1; i <= m; i++) { int u, v, val; cin >> u >> v >> val; u--; v--; edge[v].push_back(Edge(u, val));//加边 in[u]++;//加度 } queue<int>q; for (int i = 0; i < n; i++) { if (in[i] == 0) { q.push(i);//度数为0的直接压进队列 ans[i] = Value(0, i);//答案数记为(0,i),0是他的latency,i是编号 } } while (!q.empty()) { int u = q.front();//队列非空的时候不断取点 q.pop(); for (int i = 0; i < edge[u].size(); i++) { int v = edge[u][i].to; //更新答案,DAG动态规划的核心步骤 ans[v].val1 = max(ans[v].val1, ans[u].val1 + edge[u][i].val); ans[v].val2 = v; in[v]--;//如果度数为0,就压进队列,也是拓扑排序的核心 if (in[v] == 0)q.push(v); } } sort(ans,ans+n); for(int i = 0; i < n; i++){//输出答案 cout<<ans[i].val2+1; if(i != n - 1) cout<<" "; } return 0; }
Python代码
import functools def cmp(x, y): #排序 if x[0] == y[0]: return x[1]-y[1] return y[0]-x[0] n, m = map(int, input().split()) edge = [[]for i in range(n)] in1 = [0]*n for i in range(m): u, v, val = map(int, input().split()) u -= 1 v -= 1 edge[v].append([u, val]) #加边 in1[u] += 1 #加度 q = [] ans = [[0, 0] for i in range(n)] for i in range(n): if (in1[i] == 0): q.append(i) #度数为0的直接压进队列 ans[i] = [0, i] #答案数记为(0,i),0是他的latency,i是编号 while (len(q) > 0): u = q[0] #队列非空的时候不断取点 q.pop(0) for now in edge[u]: v = now[0] #更新答案,DAG动态规划的核心步骤 ans[v][0] = max(ans[v][0], ans[u][0] + now[1]) ans[v][1] = v in1[v] -= 1 if (in1[v] == 0): #如果度数为0,就压进队列,也是拓扑排序的核心 q.append(v) ans.sort(key=functools.cmp_to_key(cmp)) for i in range(n): if i != n-1: print(ans[i][1]+1, end=" ") else: print(ans[i][1]+1)
Js代码
process.stdin.resume(); process.stdin.setEncoding('utf-8'); let input = ''; process.stdin.on('data', (data) => { input += data; return; }); process.stdin.on('end', () => { function cmp(x, y) { //排序 if (x[0] == y[0]) return x[1] - y[1]; return y[0] - x[0]; } input = input.split('\n'); let n = Number(input[0].split(' ')[0]); let m = Number(input[0].split(' ')[1]); let edge = new Array(n); for (let i=0;i<n;i++) edge[i]=new Array(); let in1 = new Array(n).fill(0); for (let i = 0; i < m; i++) { tmp = input[i + 1].split(' ').map(Number); u = tmp[0]; v = tmp[1]; val = tmp[2]; u -= 1; v -= 1; edge[v].push([u, val]); //加边 in1[u]++; //加度 } let q = []; let ans = new Array(n); for (let i=0;i<n;i++) ans[i]=new Array(2).fill(0); for (let i = 0; i < n; i++) { if (in1[i] == 0) { q.push(i); //度数为0的直接压进队列 ans[i] = [0, i] //答案数记为(0,i),0是他的latency,i是编号 } } while (q.length > 0) { u = q.shift(); //队列非空的时候不断取点 edge[u].forEach(element => { now = element; v = now[0]; //更新答案,DAG动态规划的核心步骤 ans[v][0] = Math.max(ans[v][0], ans[u][0] + now[1]); ans[v][1] = v; in1[v] -= 1; if (in1[v] == 0) //如果度数为0,就压进队列,也是拓扑排序的核心 q.push(v); }); } ans.sort(cmp); tmp=[]; for (let i = 0; i < n; i++) tmp.push(ans[i][1] + 1); console.log(tmp.join(' ')) })
- 1
Information
- ID
- 36
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 6
- Tags
- # Submissions
- 160
- Accepted
- 46
- Uploaded By