hdu 5313 Bipartite Graph 完全二分图 深搜 bitset应用

48 篇文章 0 订阅
32 篇文章 0 订阅

Bipartite Graph

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 577    Accepted Submission(s): 154


Problem Description
Soda has a bipartite graph with n vertices and m undirected edges. Now he wants to make the graph become a complete bipartite graph with most edges by adding some extra edges. Soda needs you to tell him the maximum number of edges he can add.

Note: There must be at most one edge between any pair of vertices both in the new graph and old graph.
 

Input
There are multiple test cases. The first line of input contains an integer T (1T100) , indicating the number of test cases. For each test case:

The first line contains two integers n and m , (2n10000,0m100000) .

Each of the next m lines contains two integer u,v (1u,vn,vu) which means there's an undirected edge between vertex u and vertex v .

There's at most one edge between any pair of vertices. Most test cases are small.
 

Output
For each test case, output the maximum number of edges Soda can add.
 

Sample Input
  
  
2 4 2 1 2 2 3 4 4 1 2 1 4 2 3 3 4
 

Sample Output
  
  
2 0
 题意,给个二分图,要求添加最多的边形成一个完全二分图。
我们知道对于一个完全二分图,其边数为 x * y;xy分别为二分图两个集合的点数。那么如果给出的一个二分图,我们知道其可能并不是一个连通图,那么,用深搜,找出若干个小的二分图,只需要,合并若干个二分图,最终使得,整个二分图的两个集合的点数越接近,那么边数最多,加的边数也就最多。用dp的方法,dp[i]表示前i个二分图所能形成的最大点数(不超过n/2),状态转移就是dp[i] = dp[i-1] + x(x为一个二分图的点数。)这里用bitset优化,虽然是O(n*n)的复杂度也能过。还有方法,是用贪心的方法。把所有的二分图随机分入到x集和y集,得到x,y.然后,把x,y直接往n/2来凑,只要o(1)的复杂度,个人觉得这种方法,没有道理吧。但是由于,反例,还真的很难找出来,如果边太少,那么这种贪心方法,x,y必然可以达到接近n/2,如果边很多,又会形成一个大的整体,所以也没多大问题吧。故这样,也能过这题。

#define N 10005
#define M 100005
#define maxn 205
#define MOD 1000000007
int n,m,a,b,c,vis[N],ans[N][2],T;
vector<int> p[N];
bitset<N> sum;
void DFS(int f,int root){
    FI(p[f].size()){
        int v = p[f][i];
        if(vis[v] == -1){
            vis[v] = 1 - vis[f];
            ans[root][vis[v]]++;
            DFS(v,root);
        }
    }
}
int main()
{
    while(S(T)!=EOF)
    {
        while(T--){
            S2(n,m);
            FI(n) p[i+1].clear();
            FI(m){
                scan_d(a);scan_d(b);
                p[a].push_back(b);
                p[b].push_back(a);
            }
            memset(vis,-1,sizeof(vis));
            fill(ans,0);
            for(int i = 0;i<= n;i++) sum[i] = 0;
            sum[0] = 1;
            for(int i= 1;i<=n;i++){
                if(vis[i] == -1){
                    vis[i] = 0;ans[i][vis[i]]++;
                    DFS(i,i);//cout<<ans[i][0]<<" i "<<ans[i][1]<<endl;
                    sum|= ( sum << ans[i][0]) | ( sum << ans[i][1]);
                }
            }
            int maxx = 0;
            for(int i = n;i>=0;i--)
                if(sum[i])
                    maxx = max(maxx,i * (n - i) - m);
            printf("%d\n",maxx);
        }
    }
    return 0;
}



Source
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值