Disease Manangement 疾病管理
$ Disease \ Manangement $ 疾病管理
·题意
已知 \(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 ;
}