要构成最大完全图,就意味着节点二分为两半乘积最大,那么该题目转化为,先对所有联通分量二分匹配,求出每个分量的两个二分值。然后求这些从每个两个里面选一个最终能够构成1-n中的哪些值,然后暴力一下即可。对于从m个二元组中每个选一个数都成最终数字,可以用普通的O(m*n)的背包但本题目n<=10000,用bitset优化背包,即可。
本体自己代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <list> #include <queue> #include <stack> #include <string> #include <set> #include <cmath> #include <bitset> #define clr(a, x) memset(a, x, sizeof a) #define ALL(a) a.begin(), a.end() #define ls (rt<<1) #define rs (ls|1) #define lson l, mid, ls #define rson mid+1, r, rs using namespace std; typedef long long LL; typedef pair<int, int> pii; const int maxn=10000+100; int n, scc_cnt, col[maxn]; int scc[maxn][3]; bool d[maxn]; vector<int> G[maxn], ans[3]; void init() { scc_cnt=0; memset(col, 0, sizeof col); memset(d, 0, sizeof d); ans[0].clear(); ans[1].clear(); clr(scc, 0); for(int i=0;i<=n;i++) G[i].clear(); } bool dfs(int u) { for(int i=0; i<G[u].size(); i++) { int v=G[u][i]; if(col[u]==col[v])return false; if(!col[v]) { col[v]=3-col[u]; scc[scc_cnt][col[v]-1]++; if(!dfs(v))return false; } } return true; } int T, m; int dp() { typedef bitset<10001> Bitset; Bitset cur; cur.set(0); for(int i=1;i<=scc_cnt;i++) { int a = scc[i][0], b = scc[i][1]; if(a == 0 && b == 0) continue; cur = cur << a | cur << b; } long long ans = 0; for(int i=1;i<=n;i++) if(cur[i]){ ans = max((long long )ans, (long long)i * (n-i) - m); } cout << ans << endl; return 0; } int main() { scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); init(); 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); } for(int i=1; i<=n; i++) if(!col[i]) { col[i]=1; scc[++scc_cnt][0]++; dfs(i); } dp(); } return 0; }
#include <string> #include <vector> #include <algorithm> #include <numeric> #include <set> #include <map> #include <queue> #include <iostream> #include <sstream> #include <cstdio> #include <cmath> #include <ctime> #include <cstring> #include <cctype> #include <cassert> #include <limits> #include <functional> #include <bitset> #define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i)) #define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i)) #define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i)) #if defined(_MSC_VER) || __cplusplus > 199711L #define aut(r,v) auto r = (v) #else #define aut(r,v) __typeof(v) r = (v) #endif #define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it) #define all(o) (o).begin(), (o).end() #define pb(x) push_back(x) #define mp(x,y) make_pair((x),(y)) #define mset(m,v) memset(m,v,sizeof(m)) #define INF 0x3f3f3f3f #define INFL 0x3f3f3f3f3f3f3f3fLL using namespace std; typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pair<int,int> > vpii; typedef long long ll; template<typename T, typename U> inline void amin(T &x, U y) { if(y < x) x = y; } template<typename T, typename U> inline void amax(T &x, U y) { if(x < y) x = y; } struct UnionFind { vector<int> data; void init(int n) { data.assign(n, -1); } bool unionSet(int x, int y) { x = root(x); y = root(y); if(x != y) { if(data[y] < data[x]) swap(x, y); data[x] += data[y]; data[y] = x; } return x != y; } bool findSet(int x, int y) { return root(x) == root(y); } int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); } int size(int x) { return -data[root(x)]; } }; int main() { int T; scanf("%d", &T); rep(ii, T) { int n, m; scanf("%d%d", &n, &m); UnionFind uf, uf2; uf.init(n); uf2.init(n * 2); rep(i, m) { int u, v; scanf("%d%d", &u, &v), -- u, -- v; uf.unionSet(u, v); uf2.unionSet(u, n + v); uf2.unionSet(n + u, v); } vi cnt1(n, 0), cnt2(n, 0); rep(i, n) { if(uf2.findSet(i, uf.root(i))) ++ cnt1[uf.root(i)]; else ++ cnt2[uf.root(i)]; } typedef bitset<10001> Bitset; Bitset cur; cur.set(0); rep(i, n) { int a = cnt1[i], b = cnt2[i]; if(a == 0 && b == 0) continue; cur = cur << a | cur << b; } ll ans = 0; rer(i, 0, n) if(cur[i]) amax(ans, (ll)i * (n-i) - m); cout << ans << endl; } return 0; }