2013程式設計之美挑戰賽複賽第二輪 招聘

2021-06-17 15:23:17 字數 3067 閱讀 3223

題目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,其中...