題目2:招聘
時間限制
: 3000ms
記憶體限制
: 256mb
描述
alice
新開了一家公司,它的下面有兩個專案,分別需要n1
和n2個人來完成。現在有
n個人前來應聘,於是
alice
通過面試來決定他們中的哪些人會被錄用。
alice
在面試中,會仔細考察他們能如何為公司的專案帶來收益。她給每個人打了兩個分值q1
和q2,表示他加入第乙個和第二專案分別能帶來的收益值。同時,她也會仔細考察他們每個人的缺點,並且給每人打了另兩個分值c1
和c2,表示他們進入每個專案可能帶來的負面效應。
alice
心目中的最優決策是,在決定好錄用哪些人以及每個人在哪個專案下工作之後,他們為公司帶來的收益總和,除以他們為專案帶來的負面效應總和,這個比值要最大。你能幫他計算出在最優決策下,這個比值為多少嗎?
前來應聘的人數總是大於等於兩個專案需求人數的總和,因此
alice
一定會恰好招n1
+n2個人,分配給第乙個專案n1
個人,分配給第二個專案n2
個人,沒有人會同時屬於兩個專案。
輸入
輸入檔案包含多組測試資料。
第一行,給出乙個整數
t,為資料組數。接下來依次給出每組測試資料。
每組資料第一行為三個用空格隔開的整數n,
n1,n
2,表示前來應聘的人數,以及兩個專案分別需要的人數。
接下來n行,每行是用空格隔開的四個整數q1
,c1,
q2,c
2,依次表示每個人在第乙個專案下的價值和負面效應,以及第二個專案下的價值和負面效應。
輸出
對於每組測試資料,輸出一行
"case #x: y"
,其中x
表示測試資料編號,
y表示最優決策下招募的人的價值總和與負面效應總和的比值,與正確答案的絕對誤差不應超過
10-6
。所有資料按讀入順序從
1開始編號。
資料範圍
t ≤ 100
1 ≤ q
1, q
2≤ 2000
1 ≤ c
1, c
2≤ 50
小資料:
0 < n
1+ n
2≤ n ≤ 50,
大資料:
0 < n
1+ n
2≤ n ≤ 500
樣例輸入1
5 2 2
12 5 8 3
9 4 9 4
7 3 16 6
11 5 7 5
18 10 6 3
樣例輸出
case #1: 2.444444
解題思路
這是一道典型的01分數規劃問題,我們想要求這樣乙個函式的最大值 f(x)/g(x)(g(x)>0), 我們只需找到最小的r,使得存在x滿足h(x)=f(x)-r*g(x)>=0,這個r即為解。而這個r可以通過二分來確定。我們現在只需在給定r的條件下,求解f(x)-r*g(x)的最大值即可。
在這道問題中,f(x)=sum(q1[i])+sum(q2[j]) (i in s1, j in s2),g(x)=sum(c1[i])+sum(c2[j]) (i in s1, j in s2), 我們需要確定出兩個集合s1,s2,使得f(x)-r*g(x)最大,即h(x)=sum(q1[i]-r*c1[i])+sum(q2[j]-r*c2[j])(i in s1, j in s2)。這裡我們只需用動態規劃來求解。令f[i][j][k]表示,在前i個人之中,有j個人屬於s1,有k個人屬於s2,此時最大的h(x)函式值為多少,轉移很好考慮,即下乙個人分在哪個專案或者不招進來。這樣便能找到最大的h(x)。
僅僅做到這裡還是不夠,考慮到資料範圍,這種做法可能會超時。一種優化思路是,當s1集合的人定下來時時,s2集合中的人一定可以貪心地選擇剩餘人中q2[j]-r*c2[j]值最大的前n2個人,由此我們修改這個演算法,先將所有人按q2[j]-r*c2[j]從大到小排序,然後令f[i][j]表示前i個人之中,有j個人屬於s2,並且不屬於s1的人自動選前n2個人屬於s2,此時h(x)的最大值。轉移方式類似。如此一來,時間複雜度會下降乙個階,可以解決這道題目。
#include #include #include #include #include #include #include #include #include using namespace std;
const int maxn = 505;
int n, n1, n2;
int q1[maxn], c1[maxn], q2[maxn], c2[maxn];
paira[maxn];
double f[maxn][maxn];
bool ok(double ans)
sort(a + 1, a + n + 1);
reverse(a + 1, a + n + 1);
double res = 0;
f[0][0] = 0;
for (int i = 1; i <= n; ++i)
if (i <= n2) f[i][i] = f[i - 1][i - 1] + a[i].second;
} for (int i = n1 + n2; i <= n; ++i)
res = max(res, f[i][n2]);
return res > 0;
}void work()
double f = 0, r = 20000;
for (int tmp = 0; tmp < 70; ++tmp)
printf("%.6f\n", (f+r)/2);
}int main()
return 0;
}
2013程式設計之美挑戰賽 集會
description 在一條河的一側,分布著 n 個村莊。這些村莊平日裡需要一些 往來,然而商人們來回走遍每一座村莊是非常辛苦的,於是他們決定每個月都在河邊舉行一次集會,大家都來集會上購買需要的物品。然而在集會地點的選擇上,大家卻有分歧,因為誰都不願意集會的地點離自己村莊非常遠。經過一番激烈的討論...
2013程式設計之美全國挑戰賽
description alice和bob都要向同乙個商人購買鑽石。商人手中有 n 顆鑽石,他會將它們一顆顆地賣給他們,alice和bob通過競價的方式來決定鑽石的歸屬。具體的過程如下 商人首先指定其中乙個人開始 之後兩人輪流 要求是一定要比對方報的 更高。任何時候,如果乙個人不願出價或者出不起價錢...
2013程式設計之美全國挑戰賽
description 對於兩個長度相等的字串,我們定義其距離為對應位置不同的字元數量,同時我們認為距離越近的字串越相似。例如,0123 和 0000 的距離為 3,0123 和 0213 的距離則為 2,所以與 0000 相比,0213 和 0123 最相似。現在給定兩個字串 s1 和 s2,其中...