這道題的題意就是有n個點,每個點都有鄰居,問你依靠這些關係,一共可以組成幾個完整的網絡
思路
這道題因爲數據最大才16,所以可以用狀態壓縮去做,0代表不經過,1代表經過。這樣枚舉肯定不會超時的,然後用cover數組記錄的是每個狀態的下一狀態。然後狀態轉移方程就好寫了,F(s)=max(F(s),F(S^S0)這個表示的是當前狀態的剩餘沒用到的點+1)
AC代碼:
/* ***********************************************
Author :yzkAccepted
Created Time :2016/5/25 12:24:23
TASK :ggfly.cpp
LANG :C++
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
const int maxn=1<<17;
int cover[maxn],a[maxn],ans[maxn];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,i,j,k,cas=1,m;
while(~scanf("%d",&n) && n)
{
memset(a,0,sizeof(a));
memset(ans,0,sizeof(ans));
for(i=0;i<n;i++)
{
scanf("%d",&m);
a[i]=1<<i;
while(m--)
{
scanf("%d",&k);
a[i]=a[i]|(1<<k);
}
}
int all=(1<<n)-1;
for(int s=0;s<=all;s++)
{
cover[s]=0;
for(i=0;i<n;i++)
{
if(s&(1<<i))
cover[s]=cover[s] | a[i];//找到當前狀態的下一步的狀態
}
}
for(int s=1;s<=all;s++)
{
ans[s]=0;
for(int s0=s;s0;s0=(s0-1)&s)//這一步是用來找到當前狀態的所有子狀態,直接把複雜度下降,寫得太美了!
if(cover[s0]== all) ans[s]=max(ans[s],ans[s^s0]+1);
}
printf("Case %d: %d\n",cas++,ans[all]);
}
return 0;
}