蓝书(算法竞赛进阶指南)刷题记录——CH5105 Cookies(贪心+DP)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/90611656

题目:CH5105.
题目大意:现在有 n n 个人 m m 块饼干,其中第 i i 个人有一个属性 g [ i ] g[i] .现在要求分配饼干,每个人都要分到至少一块饼干,若有 a [ i ] a[i] 个人分到的饼干多于第 i i 个人,则他的怒气值为 a [ i ] g [ i ] a[i]*g[i] ,求最小怒气值以及一种方案.
1 n 30 , 1 n m 5 1 0 3 1\leq n\leq 30,1\leq n\leq m\leq 5*10^3 .

贪心地想, g [ i ] g[i] 越大的人分到的饼干肯定越多.

那么先按照 g [ i ] g[i] 从大到小排序,然后考虑DP.设 f [ i ] [ j ] f[i][j] 表示前 i i 个人 j j 块饼干的最小怒气值,可以列出方程…等等这方程怎么列,这个状态里面并没有记录第 i i 个人有几块饼干啊…

赶紧看蓝书.jpg

考虑若第 i i 个人要得到大于 1 1 块饼干,那么每多 1 1 块饼干就让他前面的人多 1 1 块饼干就好了.

而如果第 i i 个人只要一块饼干,那么就大力枚举前面有几个人也只要一块饼干即可.

也就是说:
f [ i , j ] = min { f [ i ] [ j i ] , min k = 0 i 1 { f [ k ] [ j ( i k ) ] + k t = k + 1 i g [ t ] } } f[i,j]=\min \left\{ f[i][j-i],\min_{k=0}^{i-1}\left\{ f[k][j-(i-k)]+k\sum_{t=k+1}^{i}g[t] \right\} \right\}

可以通过对 g g 求前缀和优化求和式的复杂度,时间复杂度 O ( n 2 m ) O(n^2m) .

还要考虑求方案,直接记录一下上一个状态即可.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
 
#define Abigail inline void
typedef long long LL;

const int N=30,M=5000,INF=(1<<30)-1;

int n,m;
struct person{
  int g,id;
}a[N+9];
int ans[N+9];

bool cmp(const person &a,const person &b){return a.g>b.g;}

struct state{
  int v,h0,h1;
}dp[N+9][M+9];

void Dfs_plan(int n0,int n1){
  if (!n0) return;
  Dfs_plan(dp[n0][n1].h0,dp[n0][n1].h1);
  if (n0==dp[n0][n1].h0)
    for (int i=1;i<=n0;++i) ++ans[a[i].id];
  else
    for (int i=dp[n0][n1].h0+1;i<=n0;++i) ans[a[i].id]=1;
}

Abigail into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;++i){
    scanf("%d",&a[i].g);
    a[i].id=i;
  }
}

Abigail work(){
  sort(a+1,a+1+n,cmp);
  for (int i=1;i<=n;++i) a[i].g+=a[i-1].g;
  for (int i=0;i<=n;++i)
    for (int j=0;j<=m;++j)
      dp[i][j].v=INF;
  dp[0][0].v=0;
  for (int i=1;i<=n;++i)
    for (int j=i;j<=m;++j){
      dp[i][j].v=dp[i][j-i].v;
      dp[i][j].h0=i;dp[i][j].h1=j-i;
      for (int k=0;k<i;++k)
        if (dp[k][j-i+k].v+k*(a[i].g-a[k].g)<dp[i][j].v){
          dp[i][j].v=dp[k][j-i+k].v+k*(a[i].g-a[k].g);
          dp[i][j].h0=k;dp[i][j].h1=j-i+k;
		}
	}
  Dfs_plan(n,m);
}
 
Abigail outo(){
  printf("%d\n",dp[n][m].v);
  for (int i=1;i<=n;++i)
    printf("%d ",ans[i]);
  puts("");
}

int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/90611656