1. 程式人生 > >Hackers' Crackdown UVA - 11825 (狀壓dp)

Hackers' Crackdown UVA - 11825 (狀壓dp)

存在 map ios sig memset hide vector none algo

給出n個電腦,每個電腦連著n個服務,然後每個電腦都連著m個鄰電腦,如果當前的電腦某個服務被斷開了,相鄰的電腦的服務也會被斷開,每個電腦都只能操作一次,問你最多可以讓多少種服務被斷開。一種服務被斷開的條件就是存在一個破壞第i個電腦的集合,這個集合擴散出去的集合是全集(......語文真的是......講不出來)

先把每個電腦和鄰電腦的狀態記錄下來,把這個看成一個集合,然後那麽我現在的問題就變成了用一些電腦的集合並起來使他變成全集。

現在把n個電腦的可能狀態全部枚舉出來,然後看當前這些電腦最多可以影響多少電腦,把這種狀態記錄下來,然後在開始dp

dp[電腦的所有可能狀態] = 當前狀態可以獲得的最大方案數

所以我現在可以枚舉破壞電腦的狀態,然後去找這個狀態的子集,如果我的子集可以影響的範圍是全集的話,那麽我的dp狀態就是dp[i] = max(dp[i], dp[i^j]+1),表示我可能從補集+1或者自己原本的最大值。

技術分享圖片
#include<map>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include
<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define lowbit(x) (x & (-x)) typedef unsigned long long int ull; typedef long long int ll; const double pi = 4.0*atan(1.0); const int inf = 0x3f3f3f3f; const int maxn = 1 << 17; const int maxm = 40000
; const int mod = 1000000007; using namespace std; int n, m, tol; int dp[maxn]; int state[maxn]; int num[20]; void init() { memset(dp, 0, sizeof dp); memset(num, 0, sizeof num); memset(state, 0, sizeof state); } int main() { int cas = 1; while(scanf("%d", &n), n) { init(); for(int i=0; i<n; i++) { num[i] = 1 << i; scanf("%d", &m); while(m--) { int tmp; scanf("%d", &tmp); num[i] |= (1 << tmp); } } tol = 1 << n; for(int i=0; i<tol; i++) { state[i] = 0; for(int j=0; j<n; j++) { if(i & (1 << j)) { state[i] |= num[j]; } } } for(int i=0; i<tol; i++) { for(int j=i; j; j=(j-1) & i) { if(state[j] == tol - 1) { dp[i] = max(dp[i], dp[i^j] + 1); } } } printf("Case %d: %d\n", cas++, dp[tol-1]); } return 0; }
View Code

Hackers' Crackdown UVA - 11825 (狀壓dp)