[多校联考2019(Round 5 T2)]蓝精灵的请求(二分图染色+背包)

Posted birchtree

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[多校联考2019(Round 5 T2)]蓝精灵的请求(二分图染色+背包)相关的知识,希望对你有一定的参考价值。

[多校联考2019(Round 5)]蓝精灵的请求(二分图染色+背包)

题面

在山的那边海的那边住着 n 个蓝精灵,这 n 个蓝精灵之间有 m 对好友关系,现在蓝精灵们想要玩一个团队竞技游戏,需要分为两组进行,且每一组中任意两个蓝精灵都是好友。另外,他们还想要最小化每组蓝精灵内部的好友关系数之和。蓝精灵们怎么都想不到如何分组来进行游戏,所以找到你来帮助他们分组。(若第一组内部的好友关系数为 cnt1,第二组内部的好友关系数为 cnt2,则“每组蓝精灵内部的好友关系数之和”为 cnt1+cnt2)

\(n \leq 700\)

分析

实际上就是将一个图分成两个子图,使得每一个子图都是完全图。注意到没有边直接相连的点不能放在一个子图里。因此建原图的补图。那么补图中有边相连的点不能放在一个子图里。看到这个条件,我们想到了二分图染色。

于是我们对补图二分图染色。发现同一个联通块里相同颜色的点一定在同一个子图里。不同联通块里的两个点无论颜色都可以在一个子图里。

那么我们就可以预处理出\(f[i]\)表示是否存在一种分组方式使得某组的蓝精灵数为\(i\).具体方法是对于每个联通块,我们求出两种颜色的个数\(cnt[1],cnt[2]\),那么类似背包问题,可以用\(f[i]\)来更新\(f[i+cnt[1]],f[i+cnt[2]]\).注意要用滚动数组。

最后对于所有满足\(f[i]=1\)\(i\),求边数最小值即可

代码

#include<iostream>
#include<cstdio>
#include<cstring> 
#include<algorithm> 
#define INF 0x3f3f3f3f
#define maxn 700 
using namespace std;
int n,m;
int g[maxn+5][maxn+5];
int invg[maxn+5][maxn+5];//反图
int col[maxn+5];
int cnt[5];
void dfs(int x,int c)
    col[x]=c;
    cnt[c]++;
    for(int y=1;y<=n;y++)
        if(y!=x&&g[x][y]==0)
            if(!col[y]) dfs(y,3-c);
            else if(col[y]==c)
                printf("-1\n");
                exit(0);
            
        
     
 

inline int get_e(int x)
    return x*(x-1)/2;


int f[2][maxn+5];
//类似背包,记录能不能凑出一组点数为i的子图 
int main()
    int u,v;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d %d",&u,&v);
        g[u][v]=1;
        g[v][u]=1; 
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j&&!g[i][j]) invg[i][j]=1;
        
    
    int now=1;
    f[1][0]=1;
    for(int i=1;i<=n;i++)
        if(!col[i])
            cnt[1]=cnt[2]=0;
            dfs(i,1);
            for(int j=0;j<=n;j++)
                f[now^1][j+cnt[1]]|=f[now][j];
                f[now^1][j+cnt[2]]|=f[now][j];
             
            now^=1;
            //同一个二分图联通块里,不同颜色的点不能放一起 
        
    
    int ans=INF;
    for(int i=1;i<n;i++)
        if(f[now][i]) ans=min(ans,get_e(i)+get_e(n-i));
    
    printf("%d\n",ans);

以上是关于[多校联考2019(Round 5 T2)]蓝精灵的请求(二分图染色+背包)的主要内容,如果未能解决你的问题,请参考以下文章

[多校联考2019(Round 5 T1)] [ATCoder3912]Xor Tree(状压dp)

[2019多校联考(Round 6 T3)]脱单计划 (费用流)

2022.9.11多校联考总结

2022.9.11多校联考总结

2022.9.11多校联考总结

2019多校联讯 test 3 T2