UVa 11825 黑客的攻擊(狀態壓縮dp)
阿新 • • 發佈:2017-05-30
狀態壓縮dp 題意 規劃 ace 部分 ons freopen ... 接下來
https://vjudge.net/problem/UVA-11825
題意:
假設你是一個黑客,侵入了一個有著n臺計算機(編號為0,1,...,n-1)的網絡。一共有n種服務,每臺計算機都運行著所有服務。對於每臺計算機,你都可以選擇一項服務,終止這臺計算機和所有與它相鄰計算機的該項服務。你的目標是讓盡量多的服務完全癱瘓。
思路:
數學模型:把n個集合P1,P2,P3...Pn分成盡量多組,使得每組中所有集合的並集等於全集。
因為只要每一組是全集,我們就可以破壞一個服務,分組越多,破壞的服務當然也就越多。
首先,我們用二進制來記錄每臺計算機和和它相鄰的計算機。
接下來用cover[]記錄不同的分組情況。最後就是動態規劃了,用f(s)表示子集S最多可以分成幾組,狀態轉移方程如下:
if(cover[S0]==ALL) f[S]=max(f[S],f[S0^S]+1);
如果子集S0是全集,那麽此時S0可以構成一個分組,那麽S集合中出去S0的部分最大分組就是f[S0^S]。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9#include<map> 10 using namespace std; 11 typedef long long LL; 12 typedef pair<int,int> pll; 13 const int INF=0x3f3f3f3f; 14 const int maxn=1<<16+10; 15 16 int n,m,x; 17 int p[maxn],cover[maxn],f[maxn]; 18 19 int main() 20 { 21 //freopen("D:\\input.txt","r",stdin); 22int kase=0; 23 while(~scanf("%d",&n) && n) 24 { 25 for(int i=0;i<n;i++) 26 { 27 p[i]=(1<<i); 28 scanf("%d",&m); 29 while(m--) 30 { 31 scanf("%d",&x); 32 p[i]|=(1<<x); 33 } 34 } 35 36 //枚舉分組,並計算出每組的計算機集合,也就是cover[S] 37 for(int S=0;S<(1<<n);S++) 38 { 39 cover[S]=0; 40 for(int i=0;i<n;i++) 41 { 42 if(S&(1<<i)) cover[S]|=p[i]; 43 } 44 } 45 46 f[0]=0; 47 int ALL=(1<<n)-1; 48 for(int S=1;S<(1<<n);S++) 49 { 50 f[S]=0; 51 for(int S0=S;S0;S0=(S0-1)&S) 52 { 53 if(cover[S0]==ALL) f[S]=max(f[S],f[S0^S]+1); 54 } 55 } 56 printf("Case %d: %d\n",++kase,f[ALL]); 57 } 58 return 0; 59 }
UVa 11825 黑客的攻擊(狀態壓縮dp)