求最小演员片酬

1、题目描述

多多制作人正在筹拍一部电影,需要招募一批演员。为了确保影片顺利拍摄,制作团队需要合理地分配每位演员的片酬,否则演员可能罢演。片酬的分配由团队成员共同商议决定,每位成员对演员的片酬标准有自己独特的评估意见,在团队讨论时,成员们可能会根据演员所饰演角色的杂性、表演难度、台词量等因素,提出不同的薪资调整建议。例如,某些成员认为某个角色的表演难度较大,应该给予更高的片酬;而另一些成员则认为某个角色的台词较多,也应该提高该演员的报酬。团队成员的意见可以通过会议提出,并且不同成员的意见有可能存在矛盾,每条意见以一对明确的优先顺序给出,例如,某个演员的片酬应该高于另一个演员的片酬。请你帮多多计算在满足所有制作团队成员的意见下,求出一个使得演员片酬总额最小的方案,每位演员的片酬必须至少为100元,且每次调整的增量为10元

输入描述
第一行为一个整数T, 表示共有T个测试教据(1 <= T<= 10)

每组测试教据:

第一行为两个整数n和m,分别表示招尊演员的总数和制作团队成员提出的意见数(1<=n<=10000,1<=m<=20000)

接下来的m行:
每行输入两个整数ai,bi 表示有制作团队成员认为演员ai的片酬应当比演员bi的片酬高
(1 <= ai, bi <= n)

输出描述
每组数据输出一个结果,每个结果占一行,如果满足不了所有制作团队成员的意见则输出-1


补充说明
对于20%的数据有:1 <=n<= 100,1 <= m <= 200

对于40%的数据有:1<=n<= 1000,1 <=m<= 2000

对于100%的数据有:1<=n<= 10000,1 <=m <= 20000

输入
1
7 4
7 2
4 6
2 5
7 5

输出
740


说明
演员7片酬需要比2,5高
演员4片酬需变比6高
演员2片酬需要比5高
因此总额最小的招算方案为:
演员  |演员1|演品2|演员3|演员4|演员5|演品6|演员7

[-------|-------|--------|--------|-------|--------|--------|-------|

片酬  | 100  | 110   | 100  | 110  | 100   | 100  | 120 |

总计片酬740

2、解题思路

要解决这个问题,我们需要根据给定的优先关系(即某些演员的片酬必须高于其他演员的片酬),为所有演员分配片酬,使得总片酬最小,同时满足每位演员的片酬至少为100元,且每次调整的增量为10元。如果无法满足所有优先关系(例如存在循环依赖),则返回-1。

方法思路

  1. 拓扑排序:我们需要将演员之间的优先关系建模为有向图,其中边ai -> bi表示演员ai的片酬必须高于演员bi。使用拓扑排序来检查图中是否存在环,如果存在环,则无法满足所有优先关系,返回-1。

  2. 动态分配片酬:在拓扑排序的过程中,为每个演员分配片酬。每个演员的片酬应比其所有后继节点的片酬至少高10元。初始时,所有演员的片酬设为100元。在拓扑排序中,每当处理一个节点时,其片酬应设置为所有前驱节点片酬的最大值加10元。

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        for (int t = 0; t < T; t++) {
            int n = scanner.nextInt();//演员的总数
            int m = scanner.nextInt();//制作团队成员提出的意见数
            //1.//构建图,使用邻接表graph存储优先关系,并统计每个节点入度inDegree
            List<List<Integer>> graph = new ArrayList<>();
            for (int i = 0; i <= n; i++) {
                graph.add(new ArrayList<>());
            }
            int[] inDegree = new int[n + 1]; // 因为下标从1开始
            for (int i = 0; i < m; i++) {
                int a = scanner.nextInt();
                int b = scanner.nextInt();
                graph.get(b).add(a);
                inDegree[a]++;
            }
            //使用队列进行拓扑排序
            Queue<Integer> queue = new LinkedList<>();
            //初始化所有演员片酬为100
            int[] salary = new int[n + 1];
            Arrays.fill(salary, 100);

            for (int i = 1; i <= n; i++) {
                if (inDegree[i] == 0) { // 入度为0,则入队
                    queue.offer(i);
                }
            }

            int processed = 0;
            while (!queue.isEmpty()) {
                int u = queue.poll();
                processed++;
                for (int v : graph.get(u)) {
                    if (salary[v] <= salary[u]) {
                        salary[v] = salary[u] + 10;
                    }
                    inDegree[v]--;
                    if (inDegree[v] == 0) {
                        queue.offer(v);
                    }
                }
            }

            if (processed != n) { //检查遍历得到的processed 是否与演员总数一致,如果不一致表示可能出现环,返回-1
                System.out.println(-1);
            } else {
                int total = 0;
                for (int i = 1; i <= n; i++) {
                    total += salary[i];
                }
                System.out.println(total);
            }
        }
    }

代码解释

  1. 输入处理:读取测试用例数量T,然后对于每个测试用例,读取演员数量n和意见数量m

  2. 构建图:使用邻接表graph存储优先关系,并统计每个节点的入度inDegree

  3. 拓扑排序:使用队列进行拓扑排序。初始化所有演员的片酬为100元。处理入度为0的节点,调整其邻接节点的片酬(至少比当前节点高10元),并减少邻接节点的入度。如果邻接节点的入度变为0,加入队列。

  4. 检查环:如果处理的节点数量不等于总演员数,说明存在环,输出-1。否则,计算并输出总片酬。

这种方法确保在满足所有优先关系的情况下,总片酬最小,且时间复杂度主要由拓扑排序决定,为O(n + m),适用于给定的约束条件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值