hdu5313--Bipartite Graph

题目链接:点击打开链接

问最多能加多少边为完全二分图,左右两侧有ln,rn个点,那么完全二分图有ln*rn条边,首先应该建图后,按照黑白染色的方式,分成一个二分图,分为二分图后,重新遍历边,找到在二分图中有作用的边的条数num,因为n个点是固定的,二分图中存在作用的边也是固定,如果想要加的边尽量多,就只能让二分图的总边数尽量的多,也就是让两边的点数尽量的接近,这是就用到了,之前没有任何边连接的点,因为它们可以加入左侧或右侧,通过它们让左右两侧的点数尽量的接近,这样ln*rn-num就是最多的加边数了。

#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
#include <algorithm>
using namespace std ;
#define LL __int64
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int mod = 1e9+7 ;
const double eqs = 1e-9 ;
struct node{
    int u , v ;
    int next ;
}edge[210000] ;
int head[11000] , cnt ;
int a[11000] ;
void add(int u,int v) {
    edge[cnt].u = u ; edge[cnt].v = v ;
    edge[cnt].next = head[u] ; head[u] = cnt++ ;
    edge[cnt].u = v ; edge[cnt].v = u ;
    edge[cnt].next = head[v] ; head[v] = cnt++ ;
}
void dfs(int u) {
    int i , v ;
    for(i = head[u] ; i !=-1 ; i = edge[i].next) {
        v = edge[i].v ;
        if( a[v] != -1 ) continue ;
        a[v] = 1 - a[u] ;
        dfs(v) ;
    }
}
int main() {
    int t , n , m , l_num , r_num;
    int u , v , i , j ;
    scanf("%d", &t) ;
    while(t--) {
        scanf("%d %d", &n, &m) ;
        memset(head,-1,sizeof(head)) ;
        cnt = l_num = r_num = 0 ;
        while( m-- ) {
            scanf("%d %d", &u, &v) ;
            add(u,v) ;
        }
        memset(a,-1,sizeof(a)) ;
        for(i = 1 ; i <= n ; i++) {
            if( a[i] == -1 && head[i] != -1 ) {
                a[i] = 0 ;
                dfs(i) ;
            }
        }
        int num = 0 ;
        for(u = 1 ; u <= n ; u++) {
            if( a[u] == 1 ) r_num++ ;
            else if( a[u] == 0 ) l_num++ ;
            if( a[u] ) continue ;
            for(j = head[u] ; j != -1 ; j = edge[j].next) {
                v = edge[j].v ;
                if( a[v] == 0 ) continue ;
                num++ ;
            }
        }
        int k1 , k2 , c = n-l_num-r_num ;
        k1 = max(l_num,r_num) ;
        k2 = min(l_num,r_num) ;
        if( k1 >= k1 + c ) {
            k1 += c ;
        }
        else {
            c -= k1-k2 ;
            k2 = k1 ;
            k1 += c/2 ;
            k2 += c-c/2 ;
        }
        printf("%d\n", k1*k2-num ) ;
    }
    return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值