題面
瘋狂的小金
Time Limit: 1000MS Memory limit: 65536K題目描述
自從聽說小白和小黑的友誼的小船翻了以後,小金很是開心,就和小白建立了小船,但是現在小金看到天上的n只小鳥,就萌生了一個瘋狂的想法,他決定帶着小白去打鳥,所以小金去商店買裝備—>箭,現在他知道每隻鳥的防禦力,和每一隻箭的攻擊力和價值。如果箭的攻擊力小於鳥的防禦了,小鳥是不會被打下來的。最爲奇葩的是每種箭只有一隻,小金想將小鳥都打下來,如果不能那麼小金和小白的小船又要翻啦。當然小金的資金最近比較的緊張,所以他想花費最小的錢。輸入
多組輸入,每組第一行輸入兩個數n,m(1<=n,m<=50000),表示小鳥的數量和箭的數量。接下來的一行的n個數表示每一個小鳥的防禦力,接下來的m行,每行兩個數,表示箭的攻擊力v價值w,(1<=v,w<=100000).輸出
如果小金不能將所有的小鳥射下來,輸出”No Solution”。否則輸出最小的花費。示例輸入
3 3
1 2 3
2 1
3 2
4 3示例輸出
6提示
來源
“師創杯”山東理工大學第八屆ACM程序設計競賽
解題思路
顯而易見的貪心題。只需要將鳥的防禦力按從高到低排序,將箭按攻擊力從高到底排序。然後遍歷所有的鳥,每一輪將所有能夠射殺此鳥的箭都收進一個表示當前可用弓箭的數組中,然後在當前此數組中尋找一支價值最小的箭來射殺此鳥,並將該箭從數組中移除。這樣我們的貪心策略即是對於每一隻鳥,選取當前可用弓箭中價值最小的箭,保證了每一步都是最優方案。
不過這題由於數據量很大,而且每一輪循環都要涉及加入若干元素、重新排序、刪除價值最小元素等操作,所以很容易超時。當時校賽也是 vector, set 都試了,最後換到優先隊列才過。
這樣我們就可以寫出本題的代碼了:
#include <cstdio>
#include <algorithm>
#include <functional>
#include <queue>
using namespace std;
struct info {
int v, w;
bool operator < (const info & cmp) const {
return v > cmp.v;
}
} a[50000];
int main(int argc, char const *argv[]) {
int n, m, d[50000];
while(~ scanf("%d %d", &n, &m)) {
for(int i=0; i<n; ++i) {
scanf("%d", &d[i]);
}
for(int i=0; i<m; ++i) {
scanf("%d %d", &a[i].v, &a[i].w);
}
if(n > m) {
printf("No Solution\n");
continue;
}
sort(d, d+n, greater<int>());
sort(a, a+m);
priority_queue<int, vector<int>, greater<int> > q;
bool ok = true;
long long ans = 0;
for(int i=0, j=0; i<n; ++i) {
for(; j<m; ++j) { //把剩餘弓箭中可以射殺該鳥的箭都加入到隊列中
if(a[j].v >= d[i]) q.push(a[j].w);
else break;
}
if(!q.empty()) {
ans += q.top(); //用隊首的箭(即價值最小的箭)射殺該鳥
q.pop();
}
else { //如果此鳥無箭可殺,則無解
ok = false;
break;
}
}
if(ok) printf("%lld\n", ans);
else printf("No Solution\n");
}
return 0;
}