题意:给出一张二分图,问最多在里面能加多少条边,保证还是二分图。
首先可以确定,在最后的二分图中,两个部分的点数差最小,则能保证所加边数最多。那么记录当前二分图两个部分分别的点数,对新的联通块加入当前二分图时,少的那部分点加入当前多的那部分点集中。最后对那些独立的点单独处理,即加入使得两部分的点数差最小。最后就是x*y-m,即两部分点数之积-原图变数
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cmath>
#include <time.h>
#include <vector>
#include <cstdio>
#include <string>
#include <iomanip>
///cout << fixed << setprecision(13) << (double) x << endl;
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define ls rt << 1
#define rs rt << 1 | 1
#define pi acos(-1.0)
#define eps 1e-8
#define Mp(a, b) make_pair(a, b)
#define asd puts("asdasdasdasdasdf");
typedef long long ll;
//typedef __int64 LL;
const int inf = 0x3f3f3f3f;
const int N = 10050;
const ll mod = 1e9+7;
struct node{
int v, nxt;
}e[N*20];
int head[N];
int col[N];
int deg[N];
queue <int> q;
int n, m, cnt;
int zero, one;
void init()
{
zero = one = cnt = 0;
memset( col, -1, sizeof( col ) );
memset( deg, 0, sizeof( deg ) );
memset( head, -1, sizeof( head ) );
}
void add( int u, int v )
{
e[cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
void bfs( int u )
{
while( !q.empty() ) q.pop();
int z = 0, x = 0;
col[u] = 1;
z++;
q.push( u );
while( !q.empty() ) {
u = q.front();
q.pop();
for( int i = head[u]; ~i; i = e[i].nxt ) {
int v = e[i].v;
if( col[v] != -1 )
continue;
col[v] = !col[u];
if( col[v] )
z++;
else
x++;
q.push(v);
}
}
if( z >= x ) {
zero += z;
one += x;
}
else {
zero += x;
one += z;
}
}
int main()
{
int tot;
for( scanf("%d", &tot); tot--; ) {
init();
scanf("%d%d", &n, &m);
for( int i = 1, u, v; i <= m; ++i ) {
scanf("%d%d", &u, &v);
deg[u] = deg[v] = 1;
add( u, v );
add( v, u );
}
int lp = 0;
for( int i = 1; i <= n; ++i ) {
if( !deg[i] ) {
lp++;
continue;
}
if( zero > one )
swap( zero, one );
if( col[i] == -1 )
bfs( i );
}
if( zero < one )
swap( zero, one );
int cha = zero - one;
if( lp >= cha ) {
lp -= cha;
one += cha;
}
zero += lp / 2;
one += ( lp - lp/2 );
printf("%lld\n", 1LL * zero * one - 1LL * m );
}
return 0;
}
ps:我也觉得加进的联通块策略应该是dp。。可能是数据弱了。。