Disease Manangement 疾病管理

$ Disease \ Manangement $ 疾病管理

$$HZOI$$

·题意

已知 \(n\) 个集合 \(A_i\) , $ A_i \subseteq B $ , $ B $ 中有 \(m\) 个元素 \(1,\dots,m\) ,
选定几个集合, 使 $| A_i \cup \dots \cup A_j| \le k $ , 并最大化集合的个数。 $ |A_i| $ 表示 集合 \(A_i\) 中元素的个数。

·数据范围

$m \leq 16 , n \leq 1000 $


·正解

也许...状压不一定需要 \(DP\dots\)

· \(DP\)

其实是一个非常不明显的背包 \(DP\) , 又因为是 \(01\) 背包,所以这里需要一个倒序枚举。

重要的代码放这里:

    for ( int j = ( 1 << m ) - 1 ; j >= 0 ; -- j )
    {
        for ( int i = 1 ; i <= n ; ++ tot )
        {
            dp[ j | sta[ i ] ] = max ( dp[ j | sta[ i ] ] , dp[ j ] + 1 ) ; 
        }
    }

·非 \(DP\)

其实 \(\dots\) 可以用一个实际上是一个简单枚举的过程,考虑你当前的这个点,如果你枚举到的状态按位与你第 \(i\) 个集合的状态 \(sta_i\) , 你会发现如果返回的还是 \(sta_i\) , 那使计数器自加。没有就啥也不做。思想挺优的。

#include<bits/stdc++.h>
const int N = 1e3 + 10 ; 
const int D = 16 ; 
#define int long long 
int n , m , k ; 
int a[ N ] , sta[ N ] ; 
int dp[ 1 << D + 1 ] ; 
bool flag[ 1 << D + 1 ] ; 
using namespace std ; 
int bitcount( int l )
{
    int tot = 0 ; 
    while ( l )
    {
        if( l & 1 ) tot ++ ; 
        l >>= 1 ; 
    }
    return tot ; 
}
signed main( )
{
    ios::sync_with_stdio( 0 ) ; 
    cin.tie( 0 ) ; cout.tie( 0 ) ; 
    cin >> n >> m >> k ; 
    for ( int i = 1 ; i <= n ; ++ i )
    {
        cin >> a[ i ] ; 
        int p ; 
        for ( int j = 1 ; j <= a[ i ] ; ++ j ) 
        {
            cin >> p ; 
            sta[ i ] += ( 1 << ( p - 1 ) ) ; 
        } 
    } 
    int ans = 0 ; 
    for ( int j = 0 ; j <= ( 1 << m ) - 1 ; ++ j )
    {
        int tot = 0 ; 
        for ( int i = 1 ; i <= n ; ++ i )
        {
            if( ( sta[ i ] & j ) == sta[ i ] ) 
            {
                dp[ j ] ++ ; 
            }
        }
        if( bitcount( j ) <= k ) 
        {
            ans = max( ans , dp[ j ] ) ; 
        }
    }
    cout << ans ; 
}

·结尾撒花 \(\color{pink}✿✿ヽ(°▽°)ノ✿\)

posted @ 2024-02-23 22:08  HANGRY_Sol&Cekas  阅读(15)  评论(0编辑  收藏  举报