【题目链接】
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18913
【解题报告】
《训练指南》上状态压缩DP的例题。
照样谈一些自己的体会。
这道题目有一个地方是值得学习的,就是状态压缩之后如何枚举一个集合的子集。
其他地方并没有什么难点。状态压缩之后的DP转移式很简单。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int N;
int P[20];//P[i]表示与第i台电脑表示的集合
int cover[100000]; //cover[S]表示S这个集合覆盖了多少台电脑
int dp[100000];
void init()
{
for( int i=0; i<N; i++ )
{
P[i]=1<<i;
int M; scanf( "%d",&M );
for( int j=0; j<M; j++ )
{
int num; scanf( "%d",&num );
P[i]|=1<<num;
}
}
for( int S=0; S<(1<<N ); S++ )
{
cover[S]=0;
for( int i=0; i<N; i++ )
{
if(S&(1<<i))cover[S]|=P[i];
}
}
}
int main()
{
int kase=0;
while( ~scanf("%d",&N) && N )
{
init();
memset( dp,0,sizeof dp );
int ALL=(1<<N)-1;
for( int S=0; S<(1<<N); S++ )
{
for( int S0=S; S0; S0=(S0-1)&S )
if( cover[S0]==ALL )dp[S]=max( dp[S], dp[S^S0]+1 );
}
printf( "Case %d: %d\n",++kase, dp[ALL] );
}
return 0;
}