邮票面值设计 dfs+dp

题目链接

题目大意

给定一个信封,最多只允许粘贴 N N N张邮票,计算在给定 K ( N + K ≤ 15 ) K(N+K≤15) K(N+K15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值 M A X MAX MAX,使在 1 1 1 M A X MAX MAX之间的每一个邮资值都能得到。

思路

一开始并没有啥思路,然后瞎想另一个问题,给定的k个数,最多使用n个,求 M A X MAX MAX该要怎么求。然后发现这个问题可以用 d p dp dp来解决, d p [ i ] dp[i] dp[i]代表 i i i最少使用多少个数字组成,那么转移方程为 m i n ( d p [ i − j ] + d p [ j ] ) , i > = j min(dp[i-j]+dp[j]),i>=j min(dp[ij]+dp[j]),i>=j,这里是可以优化的 m i n ( d p [ i − k j ] ) + 1 , k j min(dp[i-k_j])+1,k_j min(dp[ikj])+1,kj为所选择的某个数,为啥可以这样,也很简单,这几种情况必定包含了第一种的所有情况,而且可以发现相邻的 d p [ i ] dp[i] dp[i]最大差 1 1 1

然后我们就可以 d f s dfs dfs枚举所选择的数,然后 d p dp dp来求 M A X MAX MAX

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const double Pi = acos(-1);
namespace {
  template <typename T> inline void read(T &x) {
    x = 0; T f = 1;char s = getchar();
    for(; !isdigit(s); s = getchar()) if(s == '-') f = -1;
    for(;  isdigit(s); s = getchar()) x = (x << 3) + (x << 1) + (s ^ 48);
    x *= f;
  }
}
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (register int i = (n); i <  (m); ++i)
#define _rep(n,m,i) for (register int i = (n); i <= (m); ++i)
#define _srep(n,m,i)for (register int i = (n); i >= (m); i--)
#define _sfor(n,m,i)for (register int i = (n); i >  (m); i--)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define lowbit(x) x & (-x)
#define pii pair<int,int>
#define fi first
#define se second
const int N = 51000;
int n, k;
int dp[N], an[20], a[20], ans = 0, cnt;
int solve(int k) {
  dp[0] = 0;
  int len = 1;
  while(1) {
    int Max = INF;
    for(int i = 0; i < k; i++) {
      if(len-a[i] < 0) break;
      Max = min(Max, dp[len-a[i]]);
    }
    dp[len] = Max + 1;
    if(dp[len] >= n+1) break;
    len++;
  }
  return len; 
}
void dfs(int step) {
  if(step >= k) {
    dp[0] = 0;
    int len = solve(k);
    if(len > ans) {
      ans = len;
      for(int i = 0; i < k; i++) an[i] = a[i];
    }
    return;
  }
  int r = solve(step);
  for(int i = a[step-1]+1; i <= r; i++) {
    a[step] = i;
    dfs(step+1);
  }
}
int main() {
  read(n); read(k);
  a[0] = 1;
  dfs(1);
  for(int i = 0; i < k; i++) {
    printf("%d%c", an[i], " \n"[i==k-1]);
  }
  printf("MAX=%d\n", ans-1);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值