首先通过0,1染色找到联通分支,保存左右两边的差值,然后使左右两边的节点数目尽可能相差尽可能的小,用背包 (容量为sum/2) 求最小差异 ,这时边数最多,967MS险过
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
const int N=1e4+10;
const int MAXN=(1<<31)-1;
int INF=0x7f7f7f7f;
int T,n,m,k,tot;
const int MOD=1e9+7;
int cas=1;
vector<int> G[N];
int col[N];
int a[N];
int in[N];
void init(){
for(int i=0;i<N;i++) G[i].clear();
memset(col,-1,sizeof col);
memset(a,0,sizeof a);
tot=0;
}
void bfs(int n){
queue<int> q;
col[n]=0;
int cnt[2];
cnt[0]=1;
cnt[1]=0;
q.push(n);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(col[v]==-1){
col[v]=col[u]^1;
q.push(v);
cnt[col[v]]++;
}
}
}
if(cnt[0]>cnt[1]) a[tot]=cnt[0]-cnt[1];
else if(cnt[0]<cnt[1]) a[tot]=cnt[1]-cnt[0];
else tot--;
tot++;
}
int cha;
void build(){
for(int i=1;i<=n;i++){
if(col[i]==-1){
bfs(i);
}
}
}
void solve(){
int sum=0;
for(int i=0;i<tot;i++) sum+=a[i];
int n=sum/2;
memset(in,0,sizeof in);
in[0]=1;
for(int i=0;i<tot;i++){
for(int j=n;j-a[i]>=0;j--) in[j]=in[j-a[i]];
}
int res=n;
while(!in[res] && res>=0) res--;
cha=sum-2*res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("aaa","r",stdin);
#endif
int T;
scanf("%d",&T);
while(T--){
init();
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
build();
solve();
n-=cha;
n/=2;
printf("%d\n",n*(n+cha)-m);
}
return 0;
}