hdu 5313 Bipartite Graph

题意:
Soda有一个n个点m条边的二分图, 他想要通过加边使得这张图变成一个边数最多的完全二分图. 于是他想要知道他最多能够新加多少条边. 注意重边是不允许的.


官方题解:



分析:首先用bfs染色找出每一个连通分量的黑点,白点的数量,然后求出X*Y的最大值。

直接写的dp超时,用了题解中提到的bitset,终于过了。。。

第一次发现bitset可以这么用,很强大。


以下附上代码:

#include <algorithm>
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cctype>
#include <cmath>
#include <stack>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <bitset>


using namespace std;

typedef long long ll;
typedef unsigned long long ull;


const int maxn = 10005;
const int maxm = 100005;



struct Node{
  int v;
  int next;
};


int n,m;

struct Adlist{
  int vex[maxn];
  Node arc[maxm*2];
  int cnt;
  
  void clear(){
    for(int i = 0; i <= n; i++){
      vex[i] = -1;
    }
    cnt = 0;
  }
  
  void insert(int u, int v){
    arc[cnt].v = v;
    arc[cnt].next = vex[u];
    vex[u] = cnt;
    ++cnt;
  }
};



Adlist List;
queue<int> q;
bool vis[maxn];
bool color[maxn];
int d[maxn];
int a[maxn],b[maxn];
bitset<10005> dp;
int cnt;

int cnt1,cnt2;

void input()
{
  scanf("%d%d",&n,&m);
  
  //
  List.clear();
  fill(d,d+n+1,0);
  
  int u,v;
  for(int i = 0; i < m; i++){
    scanf("%d%d",&u,&v);
    List.insert(u,v);
    List.insert(v,u);
    ++d[u];
    ++d[v];
  }
  
}

void bfs(int s)
{
  vis[s] = 1;
  color[s] = 1;
  q.push(s);
  
  int u,v;
  while(!q.empty()){
    u = q.front(); q.pop();
    if(color[u] == 1) ++cnt1;
    else ++cnt2;
    
    for(int i = List.vex[u]; i != -1; i = List.arc[i].next){
      v = List.arc[i].v;
      if(!vis[v]){
        vis[v] = 1;
        color[v] = !color[u];
        q.push(v);
      }
    }
  }
}



void solve()
{
  fill(vis,vis+n+1,0);
  
  cnt = 0;
  int mx = 0;
  for(int i = 1; i <= n; i++){
    if(!vis[i]){      
      cnt1 = 0; 
      cnt2 = 0;
      bfs(i);
      a[cnt] = cnt1;
      b[cnt] = cnt2;
      mx += max(cnt1,cnt2);
      ++cnt;       
    }
  }

  
  dp[0] = 1;
  for(int i = 0; i < cnt; i++){
    dp = ((dp<<a[i])|(dp<<b[i]));
  }
  
  int maximum = 0;  
  for(int i = 1; i <= mx; i++) if(dp[i]) maximum = max(maximum,i*(n-i));
  
  printf("%d\n",maximum-m);
}

int main()
{
  int t;
  scanf("%d",&t);
  while(t--){
    input();
    solve();    
  }
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值