Atcoder abc187 F Close Group(動態規劃)
阿新 • • 發佈:2021-01-03
Atcoder abc187 F Close Group
題目
給出一張n個點,m條邊的無向圖,問刪除任意數量的邊後,留下來的最少數量的團的個數(\(n \le 18\) )
題解
核心:列舉狀態+動態規劃
第一次列舉狀態,對狀態進行預處理,判斷狀態裡所有的1是否能夠形成一個團
第二次列舉狀態S,再對每個狀態列舉子狀態T,假如T是一個團,那麼 就可以進行動態遞推
\[dp[S]=min(dp[S],dp[S\wedge T]+1) \]複雜度分析
狀態S中1的個數有x個,那S的子集就有 \(2^x\) 個,同時這樣的S有 \(C_{18}^x\) 個
所以最後的迴圈次數為
\[C_{18}^0*2^0+C_{18}^1*2^1+\cdots+C_{18}^x*2^x+\cdots=(1+2)^{18} \]最壞的情況是\(3^{18}\) ,3e8的複雜度
程式碼
#include<iostream> #include<algorithm> #include<cmath> #include<cstdio> #include<map> #include<cstring> using namespace std; int a[100][100]; const int N=1e6; int L[N],dp[N]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); a[x][y]=1; a[y][x]=1; } int R=1<<n; for(int S=0;S<R;S++){ int flag=1; for(int i=1;i<=n;i++){ int x1=i-1; if(!((S>>x1)&1)) continue; for(int j=i+1;j<=n;j++){ int x2=j-1; if(!((S>>x2)&1)) continue; if(a[i][j]==0){ flag=0; break; } } if(flag==0) break; } L[S]=flag; } for(int S=1;S<R;S++){ dp[S]=n+1; for(int T=S;T;T=(T-1)&S){ if(L[T]) dp[S]=min(dp[S],dp[T^S]+1); } } printf("%d\n",dp[R-1]); }