poj2724 Purifying Machine

Purifying Machine
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 5688   Accepted: 1646

Description

Mike is the owner of a cheese factory. He has 2N cheeses and each cheese is given a binary number from 00...0 to 11...1. To keep his cheese free from viruses, he made himself a purifying machine to clean virus-infected cheese. As a talented programmer, his purifying machine is built in a special way. His purifying machine has N switches, each switch has three states, 1, 0 and *. An operation of this machine is a cleaning action according to the states of the N switches. During one operation, at most one switch can be turned to state *, which can substitute for either 1 or 0. When the machine is turned to a specific state, an operation will clean all the cheeses with corresponding binary numbers. For example, if N equals 6 and the switches are turned to 01*100, the cheeses numbered 010100 and 011100 are under operation by the machine. 

One day, Mike's machine was infected. When Mike found out, he had already done some operations and the cheeses operated by this infected machine were infected too. He cleaned his machine as quickly as he could, and now he needs to clean the infected cheeses with the minimum number of operations. If a cheese is infected, cleaning this cheese with the machine one or more times will make this cheese free from virus again; but if a cheese is not infected, operation on this cheese will make it go bad. 

Now given the infected operations Mike has done, you need to find out the minimum number of operations that must be performed to clean all the infected cheeses without making any clean cheese go bad.

Input

There are several test cases. Each test case starts with a line containing two numbers N and M (1 <= N <= 10, 1 <= M <= 1000). N is the number of switches in the machine and M is the number of infected operations Mike has done. Each of the following M lines contains a switch state of the machine. A test case with N = M = 0 ends the input and should not be processed.

Output

For each test case, output one line containing an integer, which is the minimum number of operations Mike needs to do.

Sample Input

3 3
*01
100
011
0 0

Sample Output

2

Source

大致题意:给出m个长度为n的字符串,每个字符串最多有一个*,若干个0和1,*可以代表0或1,你也要用类似的字符串去匹配给定的字符串,问最少用多少个能匹配完.
分析:用包含*的字符串肯定是越多越好,那么将每两个字符串之间只差一位的连边,做二分图匹配,得到的最大匹配数就是要用的包含*的字符串的数量,剩下的只能一个一个地去匹配.
          如何判断两个字符串之间是否只差一位?先将所有的字符串转化为01串,a ^ b = c,如果c不为0并且c & (c - 1) == 0,那么a,b只差一位,c不为0代表a,b之间有差异,c - 1是挪动了一个1的位置,如果挪动了一个后没有对应的1在相同位了,说明只差1位.
          最后是二分图匹配的细节问题,这道题中不是很好分左右边,那么就当成无向图一样连边,最后求出的答案/2即可.就像是先找左边匹配的答案,再找右边匹配的答案,匹配数算了两次.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n,m,cnt,num[2020];
int a[2020],tot,ans,flag[2020],pipei[2020],map[2020][2020];
char s[2020];

bool dfs(int u)
{
    for (int i = 1; i <= tot; i++)
        if (map[u][i] && !flag[i])
        {
            flag[i] = 1;
            if (!pipei[i] || dfs(pipei[i]))
            {
                pipei[i] = u;
                return true;
            }
        }
    return false;
}

int main()
{

    while (scanf("%d%d",&n,&m) != EOF && n + m)
    {
        cnt = tot = 0;
        memset(num,0,sizeof(num));
        memset(a,0,sizeof(a));
        memset(map,0,sizeof(map));
        ans = 0;
        memset(pipei,0,sizeof(pipei));
        for (int i = 1; i <= m; i++)
        {
            scanf("%s",s + 1);
            int res = 0;
            for (int j = 1; j <= n; j++)
            {
                if (s[j] != '*')
                    res = res * 2 + s[j] - '0';
                else
                    res = res * 2;
            }
            num[++cnt] = res;
            res = 0;
            for (int j = 1; j <= n; j++)
            {
                if (s[j] != '*')
                    res = res * 2 + s[j] - '0';
                else
                    res = res * 2 + 1;
            }
            num[++cnt] = res;
        }
        sort(num + 1,num + 1 + cnt);
        a[++tot] = num[1];
        for (int i = 2; i <= cnt; i++)
            if (num[i] != num[i - 1])
                a[++tot] = num[i];
        for (int i = 1; i <= tot; i++)
            for (int j = 1; j <= tot; j++)
                if (i != j)
                {
                    int temp = a[i] ^ a[j];
                    if (temp && ((temp & (temp - 1)) == 0))
                        map[i][j] = 1;
                }
        for (int i = 1; i <= tot; i++)
        {
            memset(flag,0,sizeof(flag));
            if (dfs(i))
                ans++;
        }
        printf("%d\n",tot - ans / 2);
    }

    return 0;
}

 

posted @ 2018-01-02 14:22  zbtrs  阅读(251)  评论(0编辑  收藏  举报