POJ 2724 Purifying Machine(二分图最大匹配)

题意:给出m串长度为n的01串。有些串中可能包含*,这样的串可以表示两个串,*为1 和*为0。重复的算一种。现在我们需要消灭掉所有的01串,消灭方式有两种:

           1:一次消灭一个串。

           2:如果两个串的差别只有一位的话可以同时消灭这两个串。

           问最少多少次操作可以消灭所有的01串

思路也就是给你一些不同的(判重之后)二进制串,每个串可以通过1次操作消去,也可以把两个只有1位不同的串通过1次操作一起消去.要我们求最少的操作次数.可以把所有串按其中1的个数和是奇还是偶分成左右两个点集.对于任意两个串,如果他们只有1位不同,那么就在他们之间连接一条无向边.(这两个串一定分别属于不同的点集),因为串的个数是固定的,并且一个串可以由单独的消去或者联合消去,而要让操作的次数最少,是不是可以联想到那道基站覆盖信号的题?其实是异曲同工的,需要操作的次数最少,那自然联合消去的次数要最多,那么只要求出这个最大值,然后n减去就是答案了,显然求出这个值用的最大匹配,当然也可以不用把串特意分成左右点集,我们只需要把原图翻倍,然后求翻倍图的最大匹配数ans,最后用n-ans/2即可.类似于POJ1466


#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<iostream>
#include<string>
using namespace std;
const int maxn=1000+5;

struct Max_Match
{
    int n,m;//左右点集大小,点从1开始编号
    vector<int> g[maxn];//g[i]表示左边第i个点邻接的右边点的集合
    bool vis[maxn];//vis[i]表示右边第i个点是否在本次match中被访问过
    int left[maxn];//left[i]==j表右边第i个点与左边第j个点匹配,为-1表无点匹配

    void init(int n)
    {
        this->n=n;
   //     this->m=m;
        for(int i=1;i<=n;i++) g[i].clear();
        memset(left,-1,sizeof(left));
    }

    //判断从左u点是否可以找到一条增广路
    bool match(int u)
    {
        for(int i=0;i<g[u].size();i++)
        {
            int v=g[u][i];
            if(!vis[v])
            {
                vis[v]=true;
                if(left[v]==-1 || match(left[v]))//找到增广路
                {
                    left[v]=u;
                    return true;
                }
            }
        }
        return false;
    }

    //返回当前二分图的最大匹配数
    int solve()
    {
        int ans=0;//最大匹配数
        for(int i=1;i<=n;i++)//每个左边的节点找一次增广路
        {
            memset(vis,0,sizeof(vis));
            if(match(i)) ans++;//找到一条增广路,形成一个新匹配
        }
        return ans;
    }
}MM;
struct Node
{
	string s;
}node[maxn];
bool check(int i,int j)
{
	int num = 0;
	for (int ii = 0;ii<node[i].s.size();ii++)
	{
		if (node[i].s[ii] != node[j].s[ii])
			num++;
	}
	return num == 1;
}
int main()
{
	int n,m;
	while (scanf("%d%d",&n,&m)!=EOF && n)
	{
		int num = 0;
		set<string> s;
		for (int i = 1;i<=m;i++)
		{
			string temp;
			cin >> temp;
			if (temp.find("*") != -1)
			{
				int pos = temp.find("*");
				string s1(temp),s2(temp);
				s1[pos]='0';         //*号填充为0
				s2[pos]='1';         //*号填充为1
				if (s.find(s1) == s.end())
				{
					s.insert(s1);
					node[++num].s = s1;
				}
				if (s.find(s2) == s.end())
				{
					s.insert(s2);
					node[++num].s = s2;
				}
			}
			else
			{
				if (s.find(temp) == s.end())
				{
					s.insert(temp);
					node[++num].s = temp;
				}
			}
		}
		MM.init(num);
		for (int i = 1;i<=num;i++)
			for (int j = 1;j<=num;j++)
			{
				if (i!=j && check(i,j))
					MM.g[i].push_back(j);
			}
		printf("%d\n",num-MM.solve()/2);
	}
}

Description

Mike is the owner of a cheese factory. He has 2  N 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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值