1. 程式人生 > 其它 >【資訊學奧賽一本通——高手訓練】軟體開發 | 二分、dp

【資訊學奧賽一本通——高手訓練】軟體開發 | 二分、dp

技術標籤:資訊學奧賽一本通系列

在這裡插入圖片描述

題目大意:

現在有兩個軟體,每個軟體有 m m m個模組,有 n n n個員工,第i個員工完成 a a a軟體的一個模組需要 a i a_i ai天,完成 b b b軟體的一個模組需要 b i b_i bi天,問最少多少天可以完成兩個軟體?

題目思路:

最少問題,分析一下,如果第 x x x天可以完成,那麼第 x + 1 x+1 x+1天肯定也可以完成,所以這是一個具有單調性的題目。

所以我們可以二分這個 x x x,判斷 x x x天可以完成,那麼問題就轉換為了判斷 x x x天是否可以完成這兩個軟體的開發。因為現在固定了天數 x x x,所以對於每一個人我們可以給其分配有多少天處理 a a

a模組,有多少天處理 b b b模組。所以我們可以用 d p dp dp求解,將每個人看成一個組,每個組可以有多種選擇(多少天處理 a a a軟體),這樣就是一個分組揹包問題了: d p [ i ] [ j ] dp[i][j] dp[i][j]就代表前i個物品,處理了 a a a軟體的 j j j個模組最多能處理 b b b軟體多少個模組。

這種型別的 d p dp dp在cf上也有一個,不過沒寫題解。

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h> #include<queue> #include<algorithm> #include<string.h> #include<iostream> #define debug(x) cout<<#x<<":"<<x<<endl; #define dl(x) printf("%lld\n",x); #define di(x) printf("%d\n",x); typedef long long
ll; typedef unsigned long long ull; using namespace std; const ll INF= 1e17+7; const ll maxn = 1e7+700; const ll mod= 998244353; const double eps = 1e-9; const double PI = acos(-1); template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;} ll n,m,p; ll dp[105][105];///前i個,完成了軟體1的k個模型,軟體2最多完成幾個模型 int a[maxn],b[maxn]; int judge(int x){ memset(dp,-1,sizeof(dp)); dp[0][0] = 0; for(int i=1;i<=n;i++){ for(int j=0;j<=m;j++) dp[i][j] = dp[i-1][j]; for(int k=0;k*a[i]<=x;k++){ int op = (x - k*a[i])/b[i];///此時還能給軟體b做的貢獻 for(int j=k;j<=m;j++){ if(~dp[i-1][j-k]) dp[i][j] = max(dp[i-1][j-k]+op,dp[i][j]); } } } return dp[n][m] >= m; } int main(){ read(n);read(m); for(int i=1;i<=n;i++){ read(a[i]); read(b[i]); } int l = 1,r = 20000; int ans = 0; while(l<=r){ int mid = (l+r)/2; if(judge(mid)){ r = mid-1; ans = mid; }else l = mid+1; } printf("%d\n",ans); return 0; } /*** 2 20 16 Alexstrasza Alexstrasza ***/