ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

最少分组

2022-06-03 10:00:57  阅读:135  来源: 互联网

标签:25 连通 int 点集 枚举 最少 分组 我们


题意

给\(n\)个点(\(n\leq18\)),\(m\)条边(\(m\leq\frac{n*(n-1)}{2}\))你一个简单无向图,删去一些边(可以是0),使得图满足以下性质:

  • 任意两点\(a\),\(b\),如果\(a\),\(b\)连通,那么\(a\),\(b\)之间有边。

求满足条件最少的连通块数量。

思路

题目数据很小,状压走起!

首先我们设\(f_v\)表示当顶点集合为\(v\)时,最少的连通块数量。

然后我们先暴力枚举点集\(v\),判断这个点集\(v\)是否为完全图。

此时我们想怎么转移。

我们可以发现当\(v'\)为\(v\)的子集时,\(f_v=min(f_{v'}+f_{v-v'})\)。

所以此时我们就要枚举\(v'\)。

我们先把\(v'=v\),然后我们接下来每次都把\(v'=(v'-1)\&v\),此时\((v'-1)\&v\)肯定是\(v\)的子集,因为如果\(v'-1\)中二进制下有一位为\(1\)且\(v\)的这一位为\(0\),那么在\((v'-1)\&v\)的时候这个\(1\)就不见了,因为\(1\&0=0\)。

接下来我们来算一下时间复杂度。

在枚举\(v'\)的时候,因为\(v\)和\(v'\)的在二进制下每一位的关系只有三种情况,\(1/0\),\(1/1\),\(0/0\),也就是说,把所有枚举的情况乘起来,就是\(3^n\),虽然\(3^n\geq 3 \times 10^9\),但是因为常数很小,所以还是可以过。

Code

#include<bits/stdc++.h>
using namespace std;
int n,m,mp[25][25],f[2621445];
int main() {
    int u,v;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&u,&v),mp[u][v]=mp[v][u]=1;
    bool flag;
    memset(f,0x3f,sizeof(f));
    f[0]=0;
    for(int i=1;i<=(1<<n)-1;i++) {
        flag=true;
        for(int j=1;j<n;j++)
            if((i>>(j-1))&1)
                for(int l=j+1;l<=n;l++)
                    if((i>>(l-1))&1&&(!mp[j][l])) {
                        flag=false;
                        break;
                    }
        if(flag)
            f[i]=1;
    }
    for(int i=1;i<=(1<<n)-1;i++)
        for(int j=i;j;j=(j-1)&i)
            f[i]=min(f[i],f[j]+f[i^j]);
    printf("%d",f[(1<<n)-1]);
    return 0;
}

标签:25,连通,int,点集,枚举,最少,分组,我们
来源: https://www.cnblogs.com/konjakhzx/p/16339590.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有