1. 程式人生 > >NYG的揹包 (貪心)

NYG的揹包 (貪心)

9.19

題解

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;

const int N = 1e5+4, INF = 0x3f3f3f3f;

struct Node {
    LL aa, bb, cc;
    friend bool operator <(const Node &p, const Node &q) {
        if
(p.cc>=0 && q.cc>=0) return p.aa < q.aa; if(p.cc<0 && q.cc<0) return p.bb > q.bb; return p.cc>=0; } }aa[N]; int n,T; LL V; inline int read() { int x=0; char cc=getchar(); while (cc<'0'||cc>'9') cc=getchar(); while (cc>='0'&&cc<='9'
) x=x*10+cc-'0',cc=getchar(); return x; } int main() { freopen("backpack.in","r",stdin); freopen("backpack.out","w",stdout); T = read(); while (T--) { n = read(), V = read(); for(register int i=1; i<=n; ++i) aa[i].aa = read(), aa[i].bb = read(), aa[i].cc = aa[i].bb - aa[i].aa; sort(aa+1
, aa+n+1); bool flag = true; for(register int i=1; i<=n; ++i) { if(V < aa[i].aa) {flag = false; break;} V += aa[i].cc; } puts(flag ? "Yes" : "No"); } return 0; }

此題很有複習價值,本題中有幾個點重點:

【1】 對於可行問題要往貪心方向思考

【2】 在想貪心方案是需要嚴格證明,寧可畫上一定時間(但要控制再半小時以內)去證明正確性 , 找反例

【3】 在想貪心情況時 , 要落到實處 ,若覺得一個策略不對則需要通過題目特性落到實處看其是否正確;找反例時先感性想想反例出現情況,在去構造對應資料看是否能否定當前結論

在解決此題時 , 由於放入體積與增加體積,而且題目問題是是否可解,可使人想到貪心;

而貪心策略中,由於要是其放得下,所以可以想到先放有貢獻(增加體積)的情況 , 然後猜測是貪心順序,以a排序?b排序?還是b-a?此時發現它最後加完的體積是一個定值 , 而其體積也在不斷增加,那麼應該是a越大的放到越後面能跟保險的放下,然而是否會有反例,根據其特性:v會應為b - a > 0 而不斷增大,顯而易見策略正確;

而此題頭疼的是b - a < 0 時的策略 : 還是按照上面所述的思路 , a?,b?,b-a?,按照從大到小?從小到大?貌似從正面不好想,但有個性質時確定的:

最後的體積為定值

那麼從次特性思考,倒著來想:
最後的狀態是:

V + b1 + b2 + b3 + … + bn >= a1 + a2 + a3 + … + an

那麼最後一次選擇便是選擇先將左式減去對於的b , 在不等式成立的情況下在減去對應得a ,由於後面加上的是b - a < 0 , 那麼每次減去一組對應的a,b時左式減右式的值會越來越大 , 所以只要保證每次刪的b最小,時左式減小的儘量少,那麼等式則月容易成立,所以嘛。。。反過來想 , 不就是。。。以b為標準從大到小排序。。。
那麼全程的貪心策略則出來了:
對於 a - b > 0 的情況 以a為標準從小到大排序
對於 a - b < 0 的情況 以b為標準從大到小排序