CodeForces - Problem 1446 - Knapsack - 思維
阿新 • • 發佈:2020-11-17
CodeForces - Problem 1446 - Knapsack - 思維
對於所有物品按照重量從小到大排序,然後從後向前遍歷:
- 對於重量已經超過了\(\omega\)的物品,將其忽略掉;
- 對於重量處於\([\lceil \frac{\omega}{2} \rceil,\omega]\)的物品(如果存在),則直接選取這個物品,輸出答案
- 對於所有重量小於\(\lceil \frac{\omega}{2} \rceil\)的物品,從大到小取物品,直到取完.如果中途發現累計重量處於\([\lceil \frac{\omega}{2} \rceil,\omega]\),輸出答案; 如果取完時重量仍小於\(\lceil \frac{\omega}{2} \rceil\)
本題思維主要在於第三條: 當我們從所有重量處在\([\lceil \frac{\omega}{2} \rceil,\omega]\)的物品中挑選時:先去重量最大的物品,其重量處於\((0,\lceil \frac{\omega}{2} \rceil)\),接下來再取次大的,由於兩個物品重量都處於\((0,\lceil \frac{\omega}{2} \rceil)\),因此重量和不會超過\(\omega\); 此時判斷累計重量是否處於\([\lceil \frac{\omega}{2} \rceil,\omega]\),如果仍然不是,說明累計重量處於\((0,\lceil \frac{\omega}{2} \rceil)\)
#include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int N = 2e5+5; struct node{ ll v; int p; }; node a[N]; int ans[N]; int len; bool comp(const node&a,const node&b){ return a.v < b.v; } int find_begin(int n,ll w){ int l = 1, r = n; while(l < r){ int mid = l+r>>1; if(a[mid].v >= w){ r = mid; }else{ l = mid+1; } } return l; } int main(){ int t; scanf("%d",&t); while(t--){ len=0; int n; ll w; scanf("%d%lld",&n,&w); for(int i = 1; i <= n; i++){ scanf("%lld",&a[i].v); a[i].p = i; } sort(a+1,a+1+n,comp); int p = find_begin(n,(w+1)/2); int ptr = 0; if(a[p].v > w){ ptr = p-1; }else if(a[p].v <= w && a[p].v >= (w+1)/2){ printf("1\n%d\n",a[p].p); continue; }else{ ptr = p; } int flag = 0; ll sum = 0; for(int i = ptr; i >= 1; i--){ if(sum + a[i].v <= w){ sum += a[i].v; ans[++len] = a[i].p; } if(sum >= (w+1)/2){ flag = 1; break; } } if(flag){ sort(ans+1,ans+1+len); int first = 1; printf("%d\n",len); for(int i = 1; i <= len; i++){ if(first)first=0;else putchar(' '); printf("%d",ans[i]); } putchar('\n'); }else{ printf("-1\n"); } } // system("pause"); return 0; }