POJ2724 Purifying Machine【二分图最小边覆盖】

题目链接:

http://poj.org/problem?id=2724

题目大意:

有2^N个奶酪,编号从000…00到111…11,现在有台机器有N个开关,每个开关的状态有3个,

分别是‘0‘、‘1‘、‘*‘,每个开关只能有一个状态存在。‘*‘状态可以替代‘0‘或‘1‘状态。比如11*1,

对应为1111或1101。现在有M个奶酪被感染了,每个奶酪的编号为长度为N的二进制字符串。

和开关一样,每一位上除了能为‘1‘、‘0‘之外,还可以是‘*‘,表示既能是‘0‘,也能是‘1‘。比如说

1*1,既可以是101,也可以是111。现在要把这些被感染的奶酪(二进制字符串)都删除掉。删除

的方法有两种:

1)通过和被感染的奶酪编号一样的机器一次删除指定的一个字符串,比如说用111删除111。

2)如果有两个串只有一个字符不同,则可以用带‘*‘的字符串一次性同时删除这两个字符串(其中包

括重复的串),比如说用1*1同时删除101和111。

机器每删除一次,就要转换一次状态再进行下一次删除。问:机器最少要转换多少次状态才能将

所有串删除完。

思路:

将所有的二进制串都变为只包含01的二进制串,然后用数组Num[]来存储二进制串对应的十进制

数,比如说101对应十进制就是5。然后对Num[]数组排序,删除所有重复的数。这样子,就可以

用点来表示字符串了。假设有cnt个无重复数的点(二进制串)。然后,建立二分图,每边都是cnt个

点。对于所有满足二进制形式只差一位的两个点进行双向建边。最后问题就变为了:求二分图最小

边覆盖问题。二分图最小边覆盖 = 点数cnt - 二分图最大匹配/2。用匈牙利算法求二分图最大匹配

即可。

对于判断数A和数B的二进制形式是否只差一位,可通过 t = A^B,然后判断(t && (t&(t-1))==0),

满足,则A和B的二进制形式只差一位。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 2050;

bool Map[MAXN][MAXN],Mask[MAXN];
int NX,NY;
int cx[MAXN],cy[MAXN];

int FindPath(int u)
{
    for(int i = 1; i <= NY; ++i)
    {
        if(Map[u][i] && !Mask[i])
        {
            Mask[i] = 1;
            if(cy[i] == -1 || FindPath(cy[i]))
            {
                cy[i] = u;
                cx[u] = i;
                return 1;
            }
        }
    }
    return 0;
}

int MaxMatch()
{
    for(int i = 1; i <= NX; ++i)
        cx[i] = -1;
    for(int i = 1; i <= NY; ++i)
        cy[i] = -1;

    int res = 0;
    for(int i = 1; i <= NX; ++i)
    {
        if(cx[i] == -1)
        {
            for(int j = 1; j <= NY; ++j)
                Mask[j] = 0;
            res += FindPath(i);
        }
    }
    return res;
}

char s[12];
int Num[MAXN];
int main()
{
    int N,M;
    while(~scanf("%d%d",&N,&M) && (N||M))
    {
        memset(Map,0,sizeof(Map));
        memset(Num,0,sizeof(Num));
        int cnt = 0,k;
        for(int i = 1; i <= M; ++i)
        {
            scanf("%s",s);
            cnt++;
            k = -1;
            for(int j = 0; j < N; ++j)
            {
                if(s[j] == '*')
                    k = j;
                else
                    Num[cnt] |= ((s[j]-'0')<<j);
            }
            if(k != -1)
            {
                cnt++;
                Num[cnt] = (Num[cnt-1] | (1 << k));
            }
        }

        sort(Num+1,Num+1+cnt);
        Num[0] = -1;
        int j = 0;
        for(int i = 1; i <= cnt; ++i)
            if(Num[j] != Num[i])
                Num[++j] = Num[i];
        cnt = j;

        for(int i = 1; i <= cnt; ++i)
        {
            for(int j = i+1; j <= cnt; ++j)
            {
                int t = Num[i]^Num[j];
                if(t && (t&(t-1))==0)
                    Map[i][j] = Map[j][i] = 1;
            }
        }
        NX = NY = cnt;
        int Max = MaxMatch();
        printf("%d\n",cnt -  Max/2);
    }

    return 0;
}
时间: 2024-08-06 10:33:24

POJ2724 Purifying Machine【二分图最小边覆盖】的相关文章

POJ3020 Antenna Placement【二分图最小边覆盖】

题目链接: http://poj.org/problem?id=3020 题目大意: 在N*M的矩阵中,有K个城市要覆盖无线网.而一个无线网基站只能覆盖左右相邻或是上下相邻的两个 城市.问:至少放置多少个基站,能将这K个城市全部覆盖.输入数据时,'*'表示城市,'o'表示空地. 思路: K个城市作为K个点,编号为1~K.如果有两个城市相邻,则两个城市之间建立一条双向边.现在问题 变为了怎么从图中选择最少的边,使得能够覆盖所有的点.可以用二分图最小边覆盖来做.首先遍历 原图,对K个城市编号,存入i

POJ2724 Purifying Machine(二分图)

题意: 有2^n个奶酪,对应二进制的数,用清理机输入一个二进制数可以清理对应的奶酪,含有*的算成0和1两个,每次只能出现一个*,现在清理机自身感染细菌,它清理的奶酪都被感染,将清理机消毒后,问最少清理几次能把所有感染的奶酪清理干净. 要点: 这题比较复杂,题意就比较难看懂,算是一个有向图的最大匹配问题,因为带*的同时可以清理两个,所以就是求最多能有几个*,最后结果:总数-最大匹配数,将所有只差一位的二进制数建图,注意这个图是有向图,因为两个只差一位的数合并成一个,建图时是遍历所有的点,一个点用完

UVa1663 Purifying Machine (二分图最大匹配,最大流)

链接:http://vjudge.net/problem/UVA-1663 分析:先把原来m个模板串取出来扔进set里去重,然后将去重后的匹配串从1~cnt编号.题目说每个模板串最多一个星号“*”,所以说一个匹配串只有唯一的一个跟它只有一个位上的数字不同的另一个匹配串组合成一个模板串,这就成了二分图最大匹配问题了.然后针对每个匹配串找出和它只有一位数字不同的其它匹配串,把其编号存进数组vector<int> e[i]里.然后对cnt个匹配串以e[i][j]为状态转移进行dfs黑白染色,这样就把

POJ - 2724 Purifying Machine 二分图 最大匹配

题目大意:看了别人的题意: 给出m串长度为n的01串,如果某个串中包含'*'号的,那么这个串就可以变成两个串(因为'*'既可以表示0或者1) 比如字符串*01就可以表示成001,或者101 现在的任务是消除所有的串,给出消除串的规则如下: 1一次消灭一个串. 2如果两个串的差别只有一位的话可以同时消灭这两个串. 问至少需要多少次才能消灭这些串 解题思路:先将这些串去重,化成整数,这样就可以得到两个点集了,点集之间的关系就是一个操作能否消除掉两个串,如果可以的话,则这两个串就存在关系了 #incl

POJ2724:Purifying Machine——题解

http://poj.org/problem?id=2724 描述迈克是奶酪工厂的老板.他有2^N个奶酪,每个奶酪都有一个00 ... 0到11 ... 1的二进制数.为了防止他的奶酪免受病毒侵袭,他用一台净化机器来清理感染病毒的奶酪.净化机有N个开关,每个开关有三个状态,1,0和*.一次操作中,最多可用*一次,它可以代替1或0.当机器转到一个特定的状态时,操作将清除所有相应的二进制数字的奶酪. 有一天,迈克的机器被感染了.当麦克发现时,他已经做了一些操作,这台受感染机器操作的奶酪也被感染了.他

[POJ3020]Antenna Placement(二分图最大匹配,最小边覆盖)

题目链接:http://poj.org/problem?id=3020 题意:要求用最少的1*2的边数覆盖掉图上的所有* 在专题里看这个图很高能所以不敢做,其实是最小边覆盖的裸题,先给*标号,随后按照每个*附近是否有*来构造二分图. 最后结果 最小边覆盖 = 节点数 - 最大匹配 (虽然和最小路径覆盖结果一样,但是是完全不同的两个事情). 最大匹配是这个图上匹配的1/2,因为建图的时候是双向的. 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗

POJ 1325 Machine Schedule (二分图最小点集覆盖 匈牙利算法)

Machine Schedule Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 12621   Accepted: 5399 Description As we all know, machine scheduling is a very classical problem in computer science and has been studied for a very long history. Scheduli

二分图之最小边覆盖(poj3020)

题目:poj3020 题意:给出一个图,让你用最少的1*2的纸片覆盖掉图中的所有*出现过的地方.基本裸的最小边覆盖. 分析: 最小边覆盖 = 点总数 - 最大匹配 所以就是转化为求最大匹配. 跟前面一道题目很相似,也是相同的建图方法,奇偶性建图. #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> #incl

二分图最大匹配,最小路径覆盖,最小点覆盖,最大独立集,最小边覆盖与建图方法

转载请注明出处(别管写的好坏,码字也不容易):http://blog.csdn.net/hitwhacmer1 前言:         有自己写的,有摘的别人的,前面是摘的,也是无心整理,出错是难免的,反正我都不会证明,智人见智,别被我误导了. §1图论点.边集和二分图的相关概念和性质 点覆盖.最小点覆盖 点覆盖集即一个点集,使得所有边至少有一个端点在集合里.或者说是"点" 覆盖了所有"边"..极小点覆盖(minimal vertex covering):本身为点覆