HDU 5313 Bipartite Graph

题意:给一个二分图,问想让二分图变成完全二分图最多能加多少条边。

 

解法:图染色+dp+bitset优化。设最终的完全二分图两部分点集为A和B,A中点个数为x,B中点个数为y,边数则为x × y,答案即为x × y - m,那么用dp计算集合A中点个数的可能性。先用图染色计算每个连通分量里两种颜色点的个数,用dp[i][j]表示加入第i个连通分量时A集合中有j个点的可能性,可能为1,不可能为0,设联通分量为p,可以得到转移方程为dp[i][j] = dp[i - 1][j - p[i][0]] | dp[i - 1][j - p[i][1]],这样的复杂度为O(n ^ 2),使用bitset可以优化,bitset即为一个二进制数集,即得到dp[i] = (dp[i - 1] << p[i][0]) | (dp[i - 1] << p[i][1])。

 

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<bitset>
#define LL long long
using namespace std;
vector <int> v[10005];
int n, m;
int cnt;
int p[10005][2];
bool vis[10005];
bool color[10005];
queue <int> q;
bitset <10005> dp;
void bfs(int u)
{
    while(!q.empty())
        q.pop();
    int col[2] = {0};
    color[u] = 0;
    col[0] = 1;
    q.push(u);
    while(!q.empty())
    {
        int tmp = q.front();
        q.pop();
        int len = v[tmp].size();
        for(int i = 0; i < len; i++)
        {
            if(!vis[v[tmp][i]])
            {
                vis[v[tmp][i]] = true;
                color[v[tmp][i]] = !color[tmp];
                col[color[v[tmp][i]]]++;
                q.push(v[tmp][i]);
            }
        }
    }
    p[cnt][0] = col[0];
    p[cnt++][1] = col[1];
}
int main()
{
    int T;
    while(~scanf("%d", &T))
    {
        while(T--)
        {
            for(int i = 0; i < 10005; i++)
                v[i].clear();
            cnt = 0;
            memset(p, 0, sizeof p);
            memset(vis, 0, sizeof vis);
            memset(color, -1, sizeof color);
            scanf("%d%d", &n, &m);
            for(int i = 0; i < m; i++)
            {
                int a, b;
                scanf("%d%d", &a, &b);
                v[a].push_back(b);
                v[b].push_back(a);
            }
            for(int i = 1; i <= n; i++)
            {
                if(!vis[i])
                {
                    vis[i] = true;
                    bfs(i);
                }
            }
            dp.reset();
            dp[0] = 1;
            for(int i = 0; i < cnt; i++)
                dp = (dp << p[i][0]) | (dp << p[i][1]);
            int ans = 0;
            for(int i = 0; i <= n; i++)
            {
                if(dp[i])
                    ans = max(ans, i * (n - i));
            }
            printf("%d\n", ans - m);
        }
    }
    return 0;
}

  

posted @ 2015-07-27 09:38  露儿大人  阅读(236)  评论(0编辑  收藏  举报