【备战秋招】每日一题:2022.11.3华为机试-指令排序

为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接: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 2m+1 行: P R O − C O N PRO-CON PROCON 关系,如 ( 1   2   4 ) (1\ 2\ 4) (1 2 4) 表示编号 1 1 1 和编号 2 2 2 指令存在 P R O − C O N PRO-CON PROCON 关系,其 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(' '))
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值