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;

}

 

你可能感兴趣的:(poj)