UVA 11825 Hackers' Crackdown(狀壓DP)

這道題的題意就是有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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章