码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 5313 Bipartite Graph(dfs+背包)

时间:2015-07-27 18:31:59      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:

题意:n个点m条边,每条边的两个端点已知,求构成完全二分图能加的最多的边数;

参考:http://blog.csdn.net/acmhonor/article/details/47072399

思路:并不是一个二分图的题。。。

        n个点构成完全二分图是,两边的点数差值最小时边数最多(X+Y=n,求max(x*y));

        即在给定一些边的情况下,要求的是将点分在两个集合中数量差最小的情况;

        先求出每个联通块中的点的情况,考虑孤立点的个数,通过贪心实现剪枝;

        非贪心的情况使用背包,背包容量为n/2,推出最优解;

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int t,n,m,top,minnn;
int sum1,sum2,num,num1,num2;
int sta[2][50010];
int dp[500010];
struct node{
    int to,next;
}g[500010];
int head[500010],vis[500010];
void add(int u,int v)
{
    g[top].to=v;
    g[top].next=head[u];
    head[u]=top++;
}
void dfs(int x)
{
    if(vis[x]==-1)
        vis[x]=0;
    for(int i=head[x];i!=-1;i=g[i].next)
    {
        int v=g[i].to;
        if(vis[v]==-1)
        {
            vis[v]=1-vis[x];
            if(vis[v]==0) sum1++;
            else sum2++;
            dfs(v);
        }
    }
}
int main()
{
    int i,j,k,a,b;
    while(scanf("%d",&t)!=EOF)
    {
        while(t--)
        {
            memset(head,-1,sizeof(head));
            memset(vis,-1,sizeof(vis));
            scanf("%d%d",&n,&m);
            top=0;sum1=0;sum2=0;
            for(i=0;i<m;i++){
              scanf("%d%d",&a,&b);
              add(a,b);
              add(b,a);
            }
            top=0;num=0;num1=num2=0;
            for(i=1;i<=n;i++)
            {
                if(vis[i]==-1)
                {
                    sum1=1;sum2=0;
                    dfs(i);
                    sta[0][top]=sum1;
                    sta[1][top++]=sum2;
                    if(sum2==0){
                      num++;
                    }
                    else if(num1<num2){
                      num1+=max(sum1,sum2);
                      num2+=min(sum1,sum2);
                    }
                    else{
                      num1+=min(sum1,sum2);
                      num2+=max(sum1,sum2);
                    }
                }
            }
            if(abs(num1-num2)<=num){
               printf("%d\n",((n+1)/2)*(n/2)-m);
               continue;
            }
            int minn=-1;
            for(i=0;i<top;i++)
            {
                int ans=0;
                for(j=n/2;j>=sta[0][i]||j>=sta[1][i];j--){
                        if(j>=sta[0][i]&&ans<dp[j-sta[0][i]]+sta[0][i]&&dp[j-sta[0][i]]>=minn) //每个联通块必须选一个
                        ans=dp[j-sta[0][i]]+sta[0][i];
                        if(j>=sta[1][i]&&ans<dp[j-sta[1][i]]+sta[1][i]&&dp[j-sta[1][i]]>=minn)
                        ans=dp[j-sta[1][i]]+sta[1][i];
                        dp[j]=ans;
                        if(ans&&ans<=minnn)
                            minnn=ans;
                }
                minn=minnn;
            }
            printf("%d\n",dp[n/2]*(n-dp[n/2])-m);
        }
    }
    return 0;
}

 

hdu 5313 Bipartite Graph(dfs+背包)

标签:

原文地址:http://www.cnblogs.com/dominatingdashuzhilin/p/4680506.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!