• TTTTTTTTTTTTTTTTTT POJ 2724 奶酪消毒机 二分匹配 建图 比较难想


    Purifying Machine
    Time Limit: 2000MS   Memory Limit: 65536K
    Total Submissions: 5004   Accepted: 1444

    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

    题意:
    有2^n个奶酪,对应二进制的数,用清理机输入一个二进制数可以清理对应的奶酪,含有*的算成0和1两个,每次只能出现一个*,所以每次出现*时,能同时清除两个只有一位(*在的位)不同的二进制数,现在清理机自身感染细菌,它清理的奶酪都被感染,将清理机消毒后,问最少清理几次能把所有感染的奶酪清理干净
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <vector>
    #define MM(a,b)  memset(a,b,sizeof(a))
    using namespace std;
    
    vector<int> G[2200];
    int match[2200],used[2200];
    int g,b,m,cnt,l,r;
    int mp[2200],posi[2200];
    
    void add_edge(int u,int v)
    {
        G[u].push_back(v);
        G[v].push_back(u);
    }
    
    bool dfs(int u)
    {
         used[u]=1;
         for(int i=0;i<G[u].size();i++)
         {
           int v=G[u][i];
           int w=match[v];
           if(w<0||!used[w]&&dfs(w))
             {
                 match[u]=v;
                 match[v]=u;
                 return true;
             }
         }
         return false;
    }
    
    int  bipartite_match()
    {
        MM(match,-1);
        int res=0;
        for(int i=1;i<=1000+r;i++)
          if(match[i]<0)
          {
              memset(used,0,sizeof(used));
              if(dfs(i)) res++;
          }
        return res;
    }
    
    bool onlyonedifer(int i,int j)
    {
       int c=(i^j);
       return (c&&((c&(c-1))==0));
    }//处理i,j,两个数字二进制表示只有一位不同模板
    
    bool jione(int i)
    {
       int j=0;
       while(i)
       {
           if(i&1) j++;
           i>>=1;
       }
       return j%2==1;
    }
    
    void build()
    {
        l=0;r=0;
        for(int i=1;i<=cnt;i++)
           {
    
              if(jione(mp[i]))
                {
                    l++;
                    posi[l]=mp[i];
                }
             else
                {
                    r++;
                    posi[1000+r]=mp[i];
                }
           }
    
        for(int i=1;i<=1000+r;i++) G[i].clear();
    
        for(int i=1;i<=l;i++)
            for(int j=1;j<=r;j++)
                      if(onlyonedifer(posi[i],posi[j+1000]))
                          add_edge(i,j+1000);
    }
    
    char s[15];
    int main()
    {
        int n,m;
        while(~scanf("%d %d",&n,&m)&&(n||m))
        {
            cnt=0;
            MM(mp,0);
            for(int i=1;i<=m;i++)
                {
                    scanf("%s",s);
                    int flag=0;
                    ++cnt;
                    for(int j=0;j<n;j++)
                    {
                            if(s[j]=='*')
                              {
                                 flag=j+1;
                                 mp[cnt]=(mp[cnt]<<1)+0;
                              }
                            else
                                 mp[cnt]=(mp[cnt]<<1)+s[j]-'0';
                    }
                    if(flag)
                    {
                        mp[cnt+1]=(mp[cnt]|(1<<(n-1-(flag-1))));
                        ++cnt;
                    }
                }
            sort(mp+1,mp+cnt+1);//unique处理前先排序
            cnt=unique(mp+1,mp+cnt+1)-(mp+1);//去重
            build();
            int w=bipartite_match();
            printf("%d
    ",w+cnt-2*w);
        }
        return 0;
    }
    

      分析:细节很多的一道题;

    1.处理两个数字二进制表示只有一位不同的模板,见代码

    2.出现*时,进行二分匹配,建图很有技巧,将1出现个数为奇数次的放左边,偶数次的放右边

    3.要进行去重处理

    4.&运算符的优先级很低

     
  • 相关阅读:
    初步认识数据库系统
    相对路径与绝对路径
    数据库系统的结构抽象与演变
    unity物体穿过地面
    Matlab imadjust详解(转载)
    div水平垂直居中及块内元素居中
    Java中HashMap的使用
    Java中HashSet的使用
    Java中数组的使用
    数据结构_堆
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5504465.html
Copyright © 2020-2023  润新知