1. 程式人生 > 其它 >[luogu p1065] 作業排程方案

[luogu p1065] 作業排程方案

技術標籤:java演算法資料結構python大資料

傳送門

作業排程方案

題目描述

我們現在要利用\(m\)臺機器加工\(n\)個工件,每個工件都有\(m\)道工序,每道工序都在不同的指定的機器上完成。每個工件的每道工序都有指定的加工時間。

每個工件的每個工序稱為一個操作,我們用記號j-k表示一個操作,其中\(j\)\(1\)\(n\)中的某個數字,為工件號;\(k\)\(1\)\(m\)中的某個數字,為工序號,例如2-4表示第\(2\)個工件第\(4\)道工序的這個操作。在本題中,我們還給定對於各操作的一個安排順序。

例如,當\(n=3\)\(m=2\)時,1-1,1-2,2-1,3-1,3-2,2-2

就是一個給定的安排順序,即先安排第\(1\)個工件的第\(1\)個工序,再安排第\(1\)個工件的第\(2\)個工序,然後再安排第\(2\)個工件的第\(1\)個工序,等等。

一方面,每個操作的安排都要滿足以下的兩個約束條件。

  1. 對同一個工件,每道工序必須在它前面的工序完成後才能開始;
  2. 同一時刻每一臺機器至多隻能加工一個工件。

另一方面,在安排後面的操作時,不能改動前面已安排的操作的工作狀態。

由於同一工件都是按工序的順序安排的,因此,只按原順序給出工件號,仍可得到同樣的安排順序,於是,在輸入資料中,我們將這個安排順序簡寫為"\(1 1 2 3 3 2\)"。

還要注意,"安排順序"只要求按照給定的順序安排每個操作。不一定是各機器上的實際操作順序。在具體實施時,有可能排在後面的某個操作比前面的某個操作先完成。

例如,取\(n=3,m=2\),已知資料如下(機器號/加工時間):

工件號工序\(1\)工序\(2\)
\(1\)\(1/3\)\(2/2\)
\(2\)\(1/2\)\(2/5\)
\(3\)\(2/2\)\(1/4\)

則對於安排順序"\(1 1 2 3 3 2\)",下圖中的兩個實施方案都是正確的。但所需要的總時間分別是\(10\)\(12\)

當一個操作插入到某臺機器的某個空檔時(機器上最後的尚未安排操作的部分也可以看作一個空檔),可以靠前插入,也可以靠後或居中插入。為了使問題簡單一些,我們約定:在保證約束條件(\(1\))(\(2\))的條件下,儘量靠前插入。並且,我們還約定,如果有多個空檔可以插入,就在保證約束條件(\(1\)

)(\(2\))的條件下,插入到最前面的一個空檔。於是,在這些約定下,上例中的方案一是正確的,而方案二是不正確的。

顯然,在這些約定下,對於給定的安排順序,符合該安排順序的實施方案是唯一的,請你計算出該方案完成全部任務所需的總時間。

輸入輸出格式

輸入格式

\(1\)行為兩個正整數,用一個空格隔開:

\(m\quad n\) (其中\(m(<20)\)表示機器數,\(n(<20)\)表示工件數)

\(2\)行:個用空格隔開的數,為給定的安排順序。

接下來的\(2n\)行,每行都是用空格隔開的\(m\)個正整數,每個數不超過\(20\)

其中前\(n\)行依次表示每個工件的每個工序所使用的機器號,第\(1\)個數為第\(1\)個工序的機器號,第\(2\)個數為第\(2\)個工序機器號,等等。

後n行依次表示每個工件的每個工序的加工時間。

可以保證,以上各資料都是正確的,不必檢驗。

輸出格式

\(1\)個正整數,為最少的加工時間。

輸入輸出樣例

輸入 #1

2 3
1 1 2 3 3 2
1 2 
1 2 
2 1
3 2 
2 5 
2 4

輸出 #1

10

說明/提示

NOIP 2006 提高組 第三題

分析

這道題雖然是一道模擬題,但理解難度可不小,可以算是我見過的理解難度最大的模擬了。我理解了好久的題意才理解明白這道題要幹什麼,但理解後這道題就很簡單了。

首先題目要求我們按照給定的序列,去安排工作,每次都儘量插前檔。

那麼我們就遍歷這個給定的序列,然後遍歷當前所需做的操作的那個機器的時間線,看看能不能找到一個空閒的時間段,能夠插入當前的工作。能則插。如果前面的都插不了空擋,那就插到末尾。

思路說了,接下來是程式碼時間。

程式碼

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2020-03-31 10:56:36 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2020-03-31 11:40:15
 */
#include <iostream>
#include <cstdio>

const int maxn = 25;
const int maxm = 25;
inline int max(int a, int b) {
    return a > b ? a : b;
}

int n, m, ans;
int worknum[maxn];
int worklist[maxn * maxm];
int needmachine[maxn][maxm];
int needtime[maxn][maxm];
int finishedtime[maxn];
bool vis[maxn][maxn * maxm];

int main() {
    std :: cin >> m >> n;
    for(int i = 1; i <= n * m; i++)
        std :: cin >> worklist[i];
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            std :: cin >> needmachine[i][j];
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            std :: cin >> needtime[i][j];
    
    for(int i = 1; i <= n * m; i++) {
        int now = worklist[i];
        worknum[now]++;
        int validtime = 0;
        for(int j = finishedtime[now] + 1; ; j++) {
            if(!vis[needmachine[now][worknum[now]]][j])
                validtime++;
            else validtime = 0;
            if(validtime == needtime[now][worknum[now]]) {
                for(int k = j - needtime[now][worknum[now]] + 1; k <= j; k++)
                    vis[needmachine[now][worknum[now]]][k] = true;
                finishedtime[now] = j;
                break;
            }
        }
    }

    for(int i = 1; i <= n; i++)
        ans = max(ans, finishedtime[i]);
    std :: cout << ans << std :: endl;
    return 0;
}

評測結果

AC 100:R32336550