标签:
题意:给定二分图,求添加的最多边数,使得添加之后还是二分图
思路:如果原图可以分成X,Y两个点集,那么边数最多为|X||Y|条。由于|X|+|Y|==n,所以需要使|X|与|Y|尽量接近。先对原图进行染色,对每个连通块,求出它的两种颜色的点数差,并且交换染的颜色,染色方案依然成立。不妨设染色0和1,cnt[i]表示颜色为i的点的个数,并假设cnt[1]总是大于等于cnt[0],|X|对应cnt[1],|Y|对应cnt[0],
(1)对于同一个连通块,由于可以改变第一次染的颜色,则有:
cnt[1]-cnt[0] = ±abs(cnt[1]-cnt[0])
(2)对不同连通块,有:
cnt[1]-cnt[0]=Σ±abs(cnt[1]-cnt[0])
左边表示最后的染色为1和0的点数差,也就是|X|-|Y|,右边是一个表达式,值取决于对每一个连通块取的正负情况。于是相当于在一系列正数前面添上正负号,使得最后结果是最小的正数,注意到每个数前面必须添上正号或符号,而所有正数的和是知道的,令为V,同时令第i个正数为Ai,于是转化为以V/2为背包容量、Ai为物品体积、求背包能放满的最大体积,用V减去2倍这个答案就是等号左边的最小值了。|X|-|Y|和|X|+|Y|都出来了,求出|X|、|Y|,|X||Y|-m便是答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | /* ******************************************************************************** */ #include <iostream> // #include <cstdio> // #include <cmath> // #include <cstdlib> // #include <cstring> // #include <vector> // #include <ctime> // #include <deque> // #include <queue> // #include <algorithm> // using namespace std; // // #define pb push_back // #define mp make_pair // #define X first // #define Y second // #define all(a) (a).begin(), (a).end() // #define foreach(i, a) for (typeof(a.begin()) it = a.begin(); it != a.end(); it ++) // // void RI(vector< int >&a, int n){a.resize(n); for ( int i=0;i<n;i++) scanf ( "%d" ,&a[i]);} // void RI(){} void RI( int &X){ scanf ( "%d" ,&X);} template < typename ...R> // void RI( int &f,R&...r){RI(f);RI(r...);} void RI( int *p, int *q){ int d=p<q?1:-1; // while (p!=q){ scanf ( "%d" ,p);p+=d;}} void print(){cout<<endl;} template < typename T> // void print( const T t){cout<<t<<endl;} template < typename F, typename ...R> // void print( const F f, const R...r){cout<<f<< ", " ;print(r...);} template < typename T> // void print(T*p, T*q){ int d=p<q?1:-1; while (p!=q){cout<<*p<< ", " ;p+=d;}cout<<endl;} // // typedef pair< int , int > pii; // typedef long long ll; // typedef unsigned long long ull; // // /* -------------------------------------------------------------------------------- */ // template < typename T> bool umax(T &a, const T &b) { return a >= b? false : (a = b, true ); } const int maxn = 1e4 + 7; struct Graph { vector<vector< int > > G; void clear() { G.clear(); } void resize( int n) { G.resize(n + 2); } void add( int u, int v) { G[u].push_back(v); } vector< int > & operator [] ( int u) { return G[u]; } }; Graph G; int color[maxn], cnt[3]; void dfs( int node, int c) { color[node] = c; cnt[c] ++; for ( int i = 0; i < G[node].size(); i ++) { int v = G[node][i]; if (!color[v]) dfs(v, 3 - c); } } vector< int > dp; int a[maxn]; int get( int n, int v) { sort(a + 1, a + 1 + n); dp.clear(); dp.pb(0); int now = 0, ans = 0; bool have[12345] = { true }; for ( int i = 1; i <= n; i ++) { int sz = dp.size(); for ( int j = 0; j < sz; j ++) { int buf = dp[j] + a[i]; if (buf <= v && !have[buf]) { if (buf == v) return v; dp.pb(buf); have[buf] = true ; umax(ans, buf); } } } return ans; } int main() { #ifndef ONLINE_JUDGE freopen ( "in.txt" , "r" , stdin); #endif // ONLINE_JUDGE int T, n, m; cin >> T; while (T --) { cin >> n >> m; G.clear(); G.resize(n); for ( int i = 0; i < m; i ++) { int u, v; scanf ( "%d%d" , &u, &v); G.add(u, v); G.add(v, u); } memset (color, 0, sizeof (color)); int t = 0, total = 0; for ( int i = 1; i <= n; i ++) { if (!color[i]) { cnt[1] = cnt[2] = 0; dfs(i, 1); a[++ t] = cnt[1] - cnt[2]; if (a[t] < 0) a[t] = -a[t]; total += a[t]; } } int y = total / 2, r = total - 2 * get(t, y); cout << (n + r) / 2 * (n - r) / 2 - m << endl; } return 0; // } // // // // /* ******************************************************************************** */ |
标签:
原文地址:http://www.cnblogs.com/jklongint/p/4681718.html