1. 程式人生 > 其它 >[一本通1677/JZOJ1217/CJOJ1101]軟體開發 題解

[一本通1677/JZOJ1217/CJOJ1101]軟體開發 題解

一個軟體開發公司同時要開發兩個軟體,並且要同時交付給使用者,現在公司為了儘快完成這一任務... 這個完成天數可能否完成存在一個線性關係,所以這肯定是到二分答案的題目。問題在於如何進行判斷能否完成。

題目描述

一個軟體開發公司同時要開發兩個軟體,並且要同時交付給使用者,現在公司為了儘快完成這一任務,將每個軟體劃分成\(m\)個模組,由公司裡的技術人員分工完成,每個技術人員完成同一軟體的不同模組的所用的天數是相同的,並且是已知的,但完成不同軟體的一個模組的時間是不同的,每個技術人員在同一時刻只能做一個模組,一個模組只能由一個人獨立完成而不能由多人協同完成。一個技術人員在整個開發期內完成一個模組以後可以接著做任一軟體的任一模組。寫一個程式,求出公司最早能在什麼時候交付軟體。

輸入

輸入檔案第一行包含兩個由空格隔開的整數\(n\)\(m\)
接下來的\(n\)行每行包含兩個用空格隔開的整數\(d_1\)

\(d_2\)\(d_1\)表示該技術人員完成第一個軟體中的一個模組所需的天數,\(d_2\)表示該技術人員完成第二個軟體中的一個模組所需的天數。

輸出

輸出檔案僅有一行包含一個整數\(d\),表示公司最早能於\(d\)天后交付軟體。

輸入樣例

1 1
2 4
1 6

輸出樣例

18

提示

資料規模

對於100%的資料,\(1≤n≤100,1≤m≤100,1≤d_1,d_2≤100\)

樣例說明

最快的方案是第一個技術人員完成第二個軟體的\(18\)個模組,用時\(18\)天,第三個技術人員完成第一個軟體的\(18\)個模組,用時\(18\)天,其餘的模組由第二個技術人員完成,用時\(12\)天,做完所有的模組需要\(18\)

天。如果第一個技術人員完成第二個軟體的\(17\)個模組,第三個技術人員完成第一個軟體的\(17\)個模組,其餘的模組由第二個技術人員完成,需要用時\(18\)天,做完所有模組仍然需要\(18\)天,所以少於\(18\)天不可能做完所有模組。

思路

這個完成天數可能否完成存在一個線性關係,所以這肯定是到二分答案的題目。問題在於如何進行判斷能否完成。
首先假設 \(f_{i,j}\)表示到第\(i\)個技術人員的時候,第一個軟體已經完成了\(j\)個模組,第二個軟體可以完成的模組數量。先給出狀態轉移方程

\[f_{i,j}=\underset{0\le k \le min{\left [\frac{day}{d_{1,i}}\right ] }}{\text max} \left \{ f_{i-1,j-k}+\left [ \frac{day-k\times d_{1,i}}{d_{2,i}} \right ] \right \} \]

其中\(day\)表示二分的天數,\(k\)表示\(i\)個人抽出做程式1去做程式2的時間。
最終如果\(f_m\ge m\),那麼就可以在 \(day\) 天完成這兩個專案。
時間複雜度為 \(O(n\times m^2 \times log m)\)

程式碼

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 102;

int d1[N];
int d2[N];

int n, m;

int f[N];

inline bool check(int day)
{
    f[0] = 0;
    for (int i = 1; i <= m; i++)
        f[i] = -1e9;                                       //要保證 程式1 的 i個模組一定做的完,那就讓 做 程式1 的 i個模組 時 程式2 什麼都不要做
    for (int i = 1; i <= n; i++)                           //列舉每個人
        for (int j = m; j >= 0; j--)                       //能夠完成 軟體1 m個模組時候
            for (int k = 0; k <= min(day / d1[i], j); k++) //現在第i個人選擇抽出做 軟體1 k個模組的時間,來做 軟體2
                f[j] = max(f[j], f[j - k] + (day - d1[i] * k) / d2[i]);
    return f[m] >= m; //程式1 做 m個模組的時候,程式2 也至少能完成任務
}

int main()
{
    int l = 1, r = 0;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf(" %d %d", &d1[i], &d2[i]);
        r = max(r, m * d1[i]);
        r = max(r, m * d2[i]);
    }
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid))
            r = mid;
        else
            l = mid + 1;
    }
    printf("%d", r);
    return 0;
}