加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ PKU 2724 图论 二分匹配

(2010-07-21 20:33:52)
标签:

poj

pku

2724

it

分类: 图论

题目描述:

给你n个长度为m的0,1串。

(串中如果有*,那么*既表示0,又表示1。如 *01 表示 001 和 101.)

那么,去掉重复的串,我就得到了一个无重复的0,1串的集合。

现在要把这些串都删除掉,删除的方法是(2种):

1:一次删除任意指定的一个。

2:如果有两个串仅有一个字符不同,则可以同时删除这两个。

问你,最少要多少次可以删除完。

解题报告:

由题意,可以用匹配的思想。

如果两个串之间只有一个字符不同,那么这两个串之间连接一条边。

最大的匹配数就是节省的次数。

但是乍一看上去是图匹配。但是实际上是二分匹配。

应为每个串中的1为奇数的串之间是不能匹配的(不可能只有1个不同)。

同理,偶数也是。

所以,可以按照1的奇偶性把数据分成2份,然后用2分匹配即可。

代码如下:

#include<iostream>
using namespace std;
#define size 1024
int n, m, a, b, cnt[2], g[size][size], x[2][size], match[size];
bool vst[size];
char str[13];
void judge()
{
    int k = 1, num1 = 0, num2 = 0, f1 = 0, f2 = 0;
    for(int i = a - 1; i >= 0; i--)
    {
        if (str[i] == '*')
        {
            num1 += k;
            f1++;
        }
        else
        {
            num1 += (str[i] - '0') * k;
            num2 += (str[i] - '0') * k;
            if (str[i] == '1') {f1++;f2++;}
        }
        k *= 2;
    }
    if (!vst[num1])
    {
        vst[num1] = 1;
        x[f1 % 2][cnt[f1 % 2]++] = num1;
    }
    if (!vst[num2])
    {
        vst[num2] = 1;
        x[f2 % 2][cnt[f2 % 2]++] = num2;
    }
}
bool jeo(int id1, int id2)
{
    int temp = (x[0][id1] ^ x[1][id2]);
    int num = 1;
    for(int i = 1; i <= a; i++, num *= 2)
        if (num == temp) return true;
    return false;
}
int find(int u)
{
    for(int i = 0; i < m; i++)
        if (!vst[i] && g[u][i])
        {
            vst[i] = 1;
            if (match[i] == -1 || find(match[i]) == 1)
            {
                match[i] = u;
                return 1;
            }
        }
    return 0;
}
int solve()
{
    memset(match, -1, sizeof(match));
    int ans = 0;
    for(int i = 0; i < n; i++)
    {
        memset(vst, 0, sizeof(vst));
        ans += find(i);
    }
    return ans;
}
int main()
{
    while(scanf("%d%d", &a, &b) && (a || b))
    {
        cnt[0] = cnt[1] = 0;
        memset(vst, 0, sizeof(vst));
        for(int i = 0; i < b; i++)
        {
            scanf("%s", str);
            judge();
        }
        n = cnt[0], m = cnt[1];
        memset(g, 0, sizeof(g));
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if (jeo(i, j))
                    g[i][j] = 1;
        printf("%d\n", n + m - solve());
    }
}

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有