疾病管理

农夫John面临疾病管理问题,需要决定给哪些奶牛挤奶以避免疾病混合超过K种。这是一个动态规划和状态压缩的问题。通过优化状态更新顺序,解决了考试中的难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

疾病管理

Description

最近在农夫 John 的农场上有 D(1<=D<=15) 种疾病 ( 疾病的编号为 1..D) 在奶牛当中流行。 John 想要给他的 N(1<=N<=1000) 头奶牛挤牛奶。 挤出来的牛奶都被放在一个罐子里面。 如果这些牛奶中包含了超过 K(1<=K<=D) 种的疾病, 那么这些牛奶就要全部被丢弃掉了 。 John 应该给这 N 头奶牛当中的哪些奶牛挤奶, 才能使得牛奶不被丢弃, 并且挤牛奶的数量最多呢?

Input

第一行: 三个整数 N,D 和 K
接下来有 N 行: 这当中的第 i 行描述了第 i 个奶牛得病的信息。 第一个数字 p , 表示第 i 头奶牛得了 p 种病, 接下来有 p 个数字表示这些病的编号。 如果 p 等于 0 , 表明这头奶牛很健康。

Output

输出 John 最多可以给多少头奶牛挤牛奶。

Sample Input

6 3 2
0
1 1
1 2
1 3
2 2 1
2 2 1

Sample Output

5

Hint

John 最多可以给 5 头奶牛挤牛奶。 他们的编号分别为 1,2,3,5,6. 此时这些牛奶中只包含 2种疾病, 编号为 1, 2 。 疾病种数不超过 K=2 。

Source

搜索, 动态规划,状态压缩

Solution

状态压缩

枚举每一头奶牛,并用之更新每一种中毒的情况

     f[j|num[i]] = max(f[j|num[i]], f[j] + 1);
这也就是这道题的转移方程,当前情况下不重复的中毒情况(所以用“|”)

Code

#include <cstdio>
#include <algorithm>
#include <cmath>
#define L (1 << 15)
#define LL long long
using namespace std;

int n, d, k, q, cnt, a, maxx, ans;
int f[L], num[L];

inline int lowbit(int x) {
  return x & (-x);
}

inline bool check(int x) {
  cnt = 0;
  for (int i = x; i; i -= lowbit(i)) cnt++;
  if (cnt <= k) return 1;
  return 0; 
}

int main() {
  freopen("disease.in", "r", stdin);
  freopen("disease.out", "w", stdout);
  scanf("%d %d %d", &n, &d, &k);
  for (int i = 1; i <= n; ++i) {
    scanf("%d", &q);
    for (int j = 1; j <= q; ++j) scanf("%d", &a), num[i] += (1 << (a - 1));
  }
  for (int i = 1; i <= n; ++i)
    for (int j = (1 << d) - 1; j >= 0; j--)
      f[j|num[i]] = max(f[j|num[i]], f[j] + 1);
  for (int j = 0; j < (1 << d) - 1; j++)
    if (check(j)) maxx = max(f[j], maxx);
  printf("%d\n", maxx);
  return 0;
}

 Summary

这是考试的题

考试的时候只有40分,状压打萎了

之后把状态更新的顺序及方式修改了一下就A了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值