看似二分实则暴力的放木块问题(贪心)
例一:
题意:
就是给你$n$个物品,每一个物品都有一个体积$v[i]$,然后给你$m$个箱子,问你这个箱子的最小的体积是多少才能将这些物品都放到这m个箱子里
n,m(1≤n,m≤1000),v1,v2…,vn ( 1≤v1,v2,…,vn≤1000)
1
5 3
1 2 3 4 5
Case #1: 5
题解:
乍一看这个题是个二分,实则就是一个暴力的题,直接从小到大枚举答案就行
主要是这个贪心判断的过程,从大到小依次枚举这些物品,然后能装就装,这样来判断就行
int judge(ll x){ init(); for(int i=1;i<=m;i++){ ll xx=x; for(int j=n;j>=1;j--){ if(xx-a[j]>=0&&!vis[j]){ vis[j]=1; xx-=a[j]; } } } for(int i=1;i<=n;i++){ if(!vis[i]){ return 0; } } return 1; }
Code
#include<iostream> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int maxn=1e4+100; ll a[maxn]; int vis[maxn]; ll n,m; void init(){ for(int i=1;i<=n;i++){ vis[i]=0; } } int judge(ll x){ init(); for(int i=1;i<=m;i++){ ll xx=x; for(int j=n;j>=1;j--){ if(xx-a[j]>=0&&!vis[j]){ vis[j]=1; xx-=a[j]; } } } for(int i=1;i<=n;i++){ if(!vis[i]){ return 0; } } return 1; } int main(){ int t; cin>>t; int kase=0; while(t--){ cin>>n>>m; ll sum=0; for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); sum+=a[i]; } sort(a+1,a+n+1); ll ans=1;//这有一个细节 for(ll i=sum/m;i<=sum;i++){ if(judge(i)){ ans=i; break; } } printf("Case #%d: %lld\n",++kase,ans); } }
例二:
这个题和那个差不多的,这个题是给了你这个箱子的体积,然后让你求最少需要几个箱子
#include<iostream> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int maxn=5e6+100; int a[maxn]; int b[220]; int c[maxn]; inint(){ b[0]=1; for(int i=1;i<=20;i++) { b[i]=2*b[i-1]; } } int main() { int t; inint(); int n; cin>>t; while(t--) { int w; cin>>n>>w; for(int i=0;i<=20;i++) c[b[i]]=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); c[a[i]]++; } int x; int ans=0; int lv=n; int s; while(1) { x=w; for(int i=20;i>=0;i--) { s=min(c[b[i]],x/b[i]); lv-=s; c[b[i]]-=s; x-=s*b[i]; } ans++; if(lv==0) break; } printf("%d\n",ans); } return 0; }