poj 2724 二分图最大匹配

题意:

会给出M个串,我们要做的就是将这M个串给清除了。对于任意两个串,若二进制形式只有一位不一样,那么这两个串可以在一次操作消除,否则每个操作只能消除一个串。

3 3

*01

100

011

可以代表的串是

001

101

100

011

那么我们可以先用 10*把 101 和 100 消除了,再用 0*1把001 和 011 消除了。故操作次数为 2。

解题思路:

我们可以将所有的串先化为整数,并去重。然后对二进制形式只有一位不一样的两个数,我们由含有偶数个1的数向含有奇数个1的数连边,这样就确保了一定是二分图,因为不存在同含奇数个1或同含偶数个1 的数只相差一位。最后进行求最大匹配,既是我们可以省去的操作数。所以我们求得最大独立集才是最终答案。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define Maxn 1200
using namespace std;
int graphic[Maxn][Maxn],vi[Maxn],match[Maxn],n,m,ans[Maxn],e;
int dfs(int u)//匈牙利算法
{
    int i;
    for(i=1;i<=e;i++)
    {
        if(!vi[i]&&graphic[u][i])
        {
            vi[i]=1;
            if(match[i]==-1||dfs(match[i]))
            {
                match[i]=u;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int i,j,k,Case=1,a,b,num1,num2,Exp[13];
    char str[11];
    Exp[0]=1;
    for(i=1;i<=12;i++)
        Exp[i]=Exp[i-1]*2;
    while(scanf("%d%d",&n,&m),n||m)
    {
        memset(match,-1,sizeof(match));
        memset(graphic,0,sizeof(graphic));
        memset(ans,0,sizeof(ans));
        e=0;
        for(i=1;i<=m;i++)
        {
            scanf("%s",&str);
            num1=0;num2=-1;
            for(j=n-1;j>=0;j--)
            {
                if(str[j]!='*')
                    num1+=Exp[n-j-1]*(str[j]-'0');
                else
                    num2=Exp[n-j-1];
            }
            ans[++e]=num1;
            if(num2!=-1)
                ans[++e]=num1+num2;
        }
        int num=1;
        sort(ans+1,ans+e+1);//排完序后进行去重
        for(i=2;i<=e;i++)
            if(ans[i]!=ans[num])
                ans[++num]=ans[i];
        e=num;
        for(i=1;i<=e;i++) 
        {
            for(j=i+1;j<=e;j++)
            {
                int temp=(ans[i]^ans[j]);//找出不同位
                if((temp&(temp-1))==0)//若不同位只有一位,则为0
                {
                    temp=ans[i];
                    num=0;
                    while(temp)//求出二进制数1的个数
                    {
                        num++;
                        temp=temp&(temp-1);
                    }
                    if(num%2==0)//判断1的个数是奇数还是偶数
                        graphic[i][j]=1;
                    else
                        graphic[j][i]=1;
                }
            }
        }
        num=0;
        for(i=1;i<=e;i++)
        {
            memset(vi,0,sizeof(vi));
            if(dfs(i))
                num++;
        }
        printf("%d\n",e-num);
    }
    return 0;
}

 

posted @ 2013-07-16 21:21  fangguo  阅读(295)  评论(0编辑  收藏  举报