码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-10-06 11:35:05      阅读:84      评论:0      收藏:0      [点我收藏+]

标签:处理   注意   for   cstring   define   max   ios   直接   问题   

[多校联考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)]蓝精灵的请求(二分图染色+背包)

标签:处理   注意   for   cstring   define   max   ios   直接   问题   

原文地址:https://www.cnblogs.com/birchtree/p/11626514.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!