为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接:P1029
题目内容
塔子哥最近在做一个工程,工程里面有很多的指令,假设指令 A A A : a = 1 a= 1 a=1 ;指令 B B B : b = 2 × a b=2\times a b=2×a ;
A A A 指令define了变量 a a a , B B B 指令 u s e use use 了变量 a a a , 我们称 A A A 为 P R O ( p r o d u c e r ) PRO(producer) PRO(producer) , B B B 为 C O N ( c o n s u m e r ) CON (consumer) CON(consumer) ,他们之间的延时称为 l a t e n c y latency latency
若 A A A 和 B B B 之间有多条依赖,取最大的 I a t e n c y Iatency Iatency , P R I O R I T Y ( A ) PRIORITY (A) PRIORITY(A) 表示指令 A A A 的优先级,其计算公式如下: P R I O R I T Y ( A ) = P R I O R I T Y ( B ) + l a t e n c y PRIORITY(A)= PRIORITY(B) + latency PRIORITY(A)=PRIORITY(B)+latency ;
若 A A A 有多个 C O N ( B 1 , B 2 ) CON (B1, B2) CON(B1,B2) ,其 l a t e g c y lategcy lategcy 分别为 ( L 1 , L 2 ) (L1,L2) (L1,L2) : P R I O R I T Y ( A ) = m a x ( P R I O R I T Y ( B 1 ) + L 1 , P R I O R I T Y ( B 2 ) + L 2 ) PRIORITY(A)= max (PRIORITY(B1)+ L1, PRIORITY(B2)+L2) PRIORITY(A)=max(PRIORITY(B1)+L1,PRIORITY(B2)+L2) ;
若 A A A 没有 C O N CON CON : P R I O R I T Y ( A ) = 0 PRIORITY(A)=0 PRIORITY(A)=0 ;
现有若干条指令(数据依赖没有环),编号分别为 1 , 2 , . . . , n 1,2,...,n 1,2,...,n 现需要根据其 P R I O R I T Y PRIORITY PRIORITY 对其进行排序,若两条指令的 P R I O R I T Y PRIORITY PRIORITY 相同,则根据其编号先后进行排序。
输入描述
第一行:指令数 n n n (最大不超过 100 100 100 ), 关系行数 $m $ (最大不超过 500 500 500 )
第 2 一 m + 1 2 一m+1 2一m+1 行: P R O − C O N PRO-CON PRO−CON 关系,如 ( 1 2 4 ) (1\ 2\ 4) (1 2 4) 表示编号 1 1 1 和编号 2 2 2 指令存在 P R O − C O N PRO-CON PRO−CON 关系,其 l a t e n c y = 4 latency=4 latency=4
输出描述
输出最终的排序编号: 1 2 3 1\ 2\ 3 1 2 3
样例
样例一:
输入
4 3
1 2 1
2 3 1
3 4 2
输出
1 2 3 4
样例二:
输入
3 3
1 2 1
3 1 2
3 2 1
输出
3 1 2
题目思路
题目意思比较简单,有先后关系。很明显是基于拓扑排序的算法。因为拓扑排序就是处理这种存在先后顺序的事件。然后,我们发现这题在拓扑排序的基础上添加了一个答案取最大值。那么我们用 a n s ans ans数组去维护最大值的答案。每次处理拓扑顺序的时候就更新一下答案。比如1->2,3->2这样的图,我们在拓扑排序的时候,顺便处理 a n s [ 2 ] = m a x ( a n s [ 2 ] , a n s [ 1 / 3 ] + l a t e n c y ) ans[2] = max(ans[2], ans[1/3]+latency) ans[2]=max(ans[2],ans[1/3]+latency)。
最后要我们求 l a t e n c y latency latency最大的编号, l a t e n c y latency latency一样大,编号小的在前面。所以我们排一下序。输出编号即可。
整道题可以说是DAG动态规划的板子题,也是拓扑排序的板子题。不理解的话可以去搜索一下复习一下。
代码
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(' '))
})