這題的題意是有n個電腦,每個電腦都有n個服務,然後每台電腦都和某幾台電腦相鄰,有個駭客可以在每台電腦上停止一個服務,然後這台電腦和與它相鄰的電腦上的這個服務都會停止,問最多可以停止多少個服務。
這題就是要把電腦之間的關係化成集合,因為n的範圍比較小,所以可以狀態壓縮,用(1<<n)-1表示電腦的全集,然後每台電腦及和它相鄰的電腦可以用p[i]用二進位記錄,然後就是開個cover數組,下標取全集的子集,看子集裡的這些電腦加上它們相鄰的電腦,意思是在選中的這些電腦上停止某個服務,加上它們相鄰影響到的電腦,能否覆蓋整個集合(n台電腦)。
狀態轉移時f[s]=max(f[s-s0])+1,s0是s的子集,cover[s0]=全集。
#include<iostream>#include<cstdio>#include<cctype>#include<cstdlib>#include<cmath>#include<algorithm>#include<cstring>#include<string>#include<vector>#include<queue>#include<map>#include<set>#include<sstream>#include<stack>using namespace std;#define MAX 105typedef long long LL;const double pi=3.141592653589793;const int INF=1e9;const double inf=1e20;const double eps=1e-6;int cover[70000],f[70000];int main(){int n,m,x,kase=0;int p[20];while(cin>>n&&n){kase++;for(int i=0;i<n;i++){cin>>m;p[i]=(1<<i);while(m--){cin>>x;p[i]|=(1<<x);}}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];}}f[0]=0;int all=(1<<n)-1;for(int s=0;s<=all;s++){f[s]=0;for(int s0=s;s0;s0=(s0-1)&s){if(cover[s0]==all) f[s]=max(f[s],f[s^s0]+1);}}printf("Case %d: %d\n",kase,f[all]);} return 0;}