hdu 5313 Bipartite Graph(二分图染色+dp+bitset优化)

来源:互联网 发布:iphone连不上蜂窝数据 编辑:程序博客网 时间:2024/05/17 01:00

题目链接:

点击打开链接

题目大意:

给出一张二分图,问这张二分图还能最多加多少条边?

题目分析:

这道题的思路是这样的:

1.首先对于一张二分图,我们有两个点集,两点之间存在边的一定在不同点的集合中,那么我们我们可以利用染色将每个联通快中点分成两部分。

2.若两个点集的点数分别是n,m,那么边的总数是n*m。n+m==点的总数t,n*m=n*(t-n) = t*n - n^2,所以当n和m越接近时,边数愈多。

3.所以我们利用动态规划求取,相当于每组两个物品,必须选一个,如何选取才能使结果最接近n/2;

4.如果直接dp的话,那么我们需要n^2的复杂度。一定会超时,真是忧伤..........但是有一个数据结构能够帮我们解决这个问题

首先看dp[i][j]代表选过前i组物品后能否到达j个数量,因为只存0/1,所以我们可以用bitset来存。。

然后dp[i][j] = dp[i-1][j-p[i].first] | dp[i-1][j-p[i].second]。

所以我们可以直接位运算得到,也就是偏移p[i].first和p[i].second的长度,得到就是当前的状态,那么就是O(n*位移的复杂度),得到了优化。

最后必须怀有一颗感恩的心!!!STL大法好

代码如下:

#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>#include <vector>#include <bitset>#define MAX 10007using namespace std;int t,n,m,u,v;int color[MAX];int cnt[3];//int dp[2*MAX];bitset<MAX> dp;typedef pair<int,int> PII;vector<int> e[MAX];vector<PII> p;void add ( int u , int v ){    e[u].push_back ( v );    e[v].push_back ( u );}void dfs ( int u , int c = 1){    color[u]=c;    cnt[color[u]]++;    for ( int i = 0 ; i < e[u].size() ; i++ )    {        int v = e[u][i];        if ( color[v] ) continue;        dfs ( v , 3 - color[u] );    }}void init ( ){    memset ( color , 0 , sizeof ( color ));    for ( int i = 0 ; i < MAX ; i++ )        e[i].clear();    dp.reset();    p.clear();}int main ( ){    scanf ( "%d" , &t );    while ( t-- )    {        scanf ( "%d%d" , &n , &m );        init ( );        int ans = -m;        while ( m-- )        {            scanf ( "%d%d" , &u , &v );            add ( u , v );        }        for ( int i = 1 ; i <= n ; i++ )            if (!color[i])            {                memset ( cnt , 0 , sizeof ( cnt ));                dfs ( i );                if ( cnt[1] || cnt[2] )                    p.push_back ( make_pair ( cnt[1] , cnt[2]));            }        //dp[0] = 1;        /*for ( int i = 0 ; i <  p.size() ; i++ )            for ( int j = n/2 ; j >= 1 ; j-- )                if ( ( j >=  p[i].first&&dp[j-p[i].first])                    ||( j >=p[i].second&&dp[j-p[i ].second]) )                    dp[j] = 1;*/        //dp.reset();        //cout << "YES" << endl;        dp[0] = 1;        for ( int i = 0 ; i < p.size() ; i++ )            dp = dp<<p[i].first | dp<<p[i].second;        int mid;        for ( int i = 0 ;; i++ )        {            if ( dp[n/2-i] )            {                mid = n/2 - i;                break;            }        }        ans += mid*(n-mid);        printf ( "%d\n" , ans );    }}


0 0
原创粉丝点击