2023.04.08 定时测试随笔

发布时间 2023-04-08 12:27:51作者: florence25

T1 [NOIP2006 提高组] 作业调度方案 (模拟)

传送门:luogu P1131


约束条件 :

  • 对于同一个工件,第 \(i\) 道工序必须要在第 \(i-1\) 道工序结束之后才能开始
  • 一个机器每一刻只能加工一道工序
  • 必须要按照题目给的顺序安排下一个工序

关于安排顺序:

一个非常神器的东西 考试的时候因为这个卡了很久

对于安排序列 1 1 2 3 3 2, \(1\) 工件在 \(2\) 工件的前面,如果没有顺序安排,\(2\) 就可以在 \(1\) 前面
\(2\) 就可以从 \(0\) 开始,那这样的话结果就会不一样,安排顺序使调度固定,最短方案有且只有一种


题目已经给出了每个工作的工序顺序以及每一道工序在哪个机器上进行,我们要做的就是
合理安排机器的使用时间使满足上面的约束条件

我们可以把每个机器看成一条 时间轴 ,在这个时间轴上去安排每一道工序,又因为约束条件
所以我们的模拟思想就是在这个时间轴上 从左到右插空,如果有一段区间是空的就插入

对于每一次插入一段工序 \(i\),我们需要维护一些东西:

  • \(i\) 道工序在哪个机器完成以及所需时间
  • \(i-1\) 道工序完成的时间的最后一刻(保证 \(i\)\(i-1\) 之后开始)
  • 在当前机器的时间轴上的某一刻是否已经有工序了(保证一个机器每一刻只加工一道)

#include <bits/stdc++.h>

using namespace std;

const int maxn = 20 + 5;
int wh[maxn][maxn], co[maxn][maxn], cnt[maxn], n, m, maxx;
int lst[maxn], mct[maxn][10005], a[maxn * maxn];//时间轴存10005

void read() {
	scanf("%d%d", &m, &n);
	for (int i = 1; i <= n * m; ++ i)
		scanf("%d", &a[i]);
	for (int i = 1; i <= n; ++ i)
		for (int j = 1; j <= m; ++ j)
			scanf("%d", &wh[i][j]);
	for (int i = 1; i <= n; ++ i)
		for (int j = 1; j <= m; ++ j)
			scanf("%d", &co[i][j]);
	for (int i = 1; i <= n * m; ++ i) {
		cnt[a[i]] ++ ;
		int now = a[i], w = wh[a[i]][cnt[a[i]]], c = co[a[i]][cnt[a[i]]];
		int p = 0;
		for (int j = lst[now] + 1; ; ++ j) {
			if (!mct[w][j])
				++ p;
			else 
				p = 0;
			if (p == c) {
				for (int k = j - c + 1; k <= j; ++ k)
					mct[w][k] = 1;
				if (j > maxx) maxx = j;
				lst[now] = j;
				break ;
			}
		}
	}
	printf("%d\n", maxx);
}

int main() {
	read();
	return 0;
}