AtCoder Beginner Contest 187 F - Close Group(狀態壓縮動態規劃)
阿新 • • 發佈:2021-01-03
差億點AK,只怪沒學過狀態壓縮動態規劃,呀嘞呀嘞dazei
列舉一個圖的子圖:
for(int i=n;i;i=(i-1)&n)
{
//i就是n的子圖
}
AtCoder Beginner Contest 187 F - Close Group
題意:給一個n(n<=18)節點m條邊的圖,刪除幾個邊後,使它變成幾個連通子圖,求最少能夠變成幾個子圖,並且全是完全圖
題解:首先列舉所有子圖,如果是完全圖,標記dp[i]=1,然後從小到大列舉,對一個非完全子圖,再列舉其子圖更新答案,由於是從小到大列舉,因此當前子圖的子圖肯定已經更新完了,所以可放心dp
#include<bits/stdc++.h> using namespace std; #define f(i,a,b) for(register int i=a;i<=b;++i) #define ll long long #define pb push_back inline int read(){int x;scanf("%d",&x);return x;} int eg[20][20],dp[1<<N]; void solve() { int n=read(),m=read(); f(i,1,m){ int x=read(),y=read(); eg[x][y]=eg[y][x]=1; } int sum=(1<<n)-1; dp[0]=999999; for(int i=1;i<=sum;++i) { vector<int>edge; for(int j=0;j<n;j++) if(i&(1<<j)) edge.pb(j+1); int flag=1; for(int j=0;flag&&j<edge.size();++j) for(int k=j+1;flag&&k<edge.size();++k) if(!eg[edge[j]][edge[k]]) flag=0; if(flag) dp[i]=1; else dp[i]=999999; } for(int i=1;i<=sum;++i) { if(dp[i]==1) continue; for(int j=i;j;j=(j-1)&i) { dp[i]=min(dp[i],dp[j]+dp[j^i]); } } cout<<dp[sum]<<endl; } int main() { int T=1; while(T--) solve(); return 0; }