ABC187 F - Close Group(状压dp)

题意:

在这里插入图片描述
给定n个点m条边的无向图,
要求删掉若干边,使得图为若干个连通块,满足每个连通块都是完全图,
问最少的连通块数量是多少。

数据范围:n<=18,m<=n(n-1)/2

解法:

n<=18,考虑状压dp:
令d[i]表示点集为i时,满足题目条件的最小连通块数量.

转移方程:
d[i]=1,此时需满足i自身是完全图.
d[i]=d[i-j]+d[j],其中j是i的子集.

code:

#include <bits/stdc++.h>
using namespace std;
#define int long long
int d[1<<20];
int e[20];//e[i]为点i的边集
int n,m;
signed main(){
    
    
    ios::sync_with_stdio(0);
    cin>>n>>m;
    for(int i=0;i<n;i++)e[i]|=(1<<i);
    for(int i=1;i<=m;i++){
    
    
        int a,b;cin>>a>>b;
        a--,b--;
        e[a]|=(1<<b);
        e[b]|=(1<<a);
    }
    //init
    for(int i=0;i<(1<<n);i++){
    
    
        d[i]=1e9;
    }
    d[0]=0;
    //dp
    for(int i=1;i<(1<<n);i++){
    
    
        //判断集合是否本身是一个完全图
        int ok=1;
        for(int j=0;j<n;j++){
    
    
            if(i>>j&1){
    
    
                if((e[j]&i)!=i){
    
    
                    ok=0;
                }
            }
        }
        if(ok)d[i]=1;
        //枚举当前集合是从何组合的
        for(int j=i;j;j=((j-1)&i)){
    
    //枚举子集
            d[i]=min(d[i],d[i-j]+d[j]);//d[i]由(i-j)和j组成.
        }
    }
    cout<<d[(1<<n)-1]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/112692869
今日推荐