• uva11205 The broken pedometer 子集生成


    PS:此题我在网上找了很久的题解,发现前面好多题解的都是没有指导意义的。后来终于找到了一篇好的题解。

    好的题解的链接:http://blog.csdn.net/u013382399/article/details/23516051

    我在他的解题的基础上,有了自己的理解。

    题意:

      有n(100以内)个位数为p(15以内)的二进制数,最少需要几个二进制位就可以把他们区分开。

    题目分析:

      数据较小,用的是暴力的方法,就是枚举每一个二进制位取或不取。就是相当于是枚举矩阵的列。

      刘汝佳的小白书120页提到的子集生成就是这样的枚举。这道题我用了位向量法。

      对于此题,某一列(一个二进制位或者说是某一盏灯)取或不取可以这样理解。不取就认为所有的n个数中这一位数是相同的,可以是全部赋值为1也可以是0。

      然后就是判断这n个数中有没有重复的数。转化为字符串好比较,当然也可以是转化为进制数比较(原来的数认为是二进制数)。

      我根据这个意思,自己写了一份代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<map>
     6 using namespace std;
     7 
     8 int n,p,cur;
     9 int ans;
    10 int a[110][20];
    11 char s[110][20];
    12 bool vis[20];
    13 map<string,int > st;
    14 int  DFS(int x)
    15 {
    16     if(x==p)
    17     {
    18         int t=0;
    19         for(int i=0;i<n;i++)
    20             for(int j=0;j<p;j++)
    21                 if(vis[j]){t++;s[i][j]=a[i][j]+48;}
    22                 else s[i][j]=48;
    23         for(int i=0;i<n;i++) s[i][p]=0;
    24         st.clear();
    25         for(int i=0;i<n;i++)
    26         {
    27             //puts(s[i]);
    28             if(!st[s[i]]) st[s[i]]=1;
    29             else return 0;
    30         }
    31         t/=n;
    32         ans=min(t,ans);
    33         return 0;
    34     }
    35     vis[x]=0;
    36     DFS(x+1);
    37     vis[x]=1;
    38     DFS(x+1);
    39     return 1;
    40 }
    41 int main()
    42 {
    43     //freopen("test.txt","r",stdin);
    44     int cas;
    45     scanf("%d",&cas);
    46     while(cas--)
    47     {
    48         scanf("%d%d",&p,&n);
    49         for(int i=0;i<n;i++)
    50             for(int j=0;j<p;j++)
    51                 scanf("%d",&a[i][j]);
    52         ans=p;
    53         memset(vis,0,sizeof(vis));
    54         DFS(0);
    55         printf("%d
    ",ans);
    56     }
    57     return 0;
    58 }
    View Code

      下面是一份看上去更简洁更暴力的代码,是我从网上找的,因为很久之前找的,所以都不知道出处了。

      它的思想是这样的:因为是p位二进制,所以范围在0 ~ 2p 。并且p是不大于15的。所以可以直接枚举。对于i属于[0,2p ],如果n个数中每个数 & i的结果没有重复,就代表i是一个可能的解,只要把i这个数二进制位为1的个数求出来,就是一个可能的答案。最后取最小值。这个的原理,我不知道,但是可以编程来验证。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<set>
    using namespace std;
    
    int a[110];
    int p,n;
    set<int > s;
    int main()
    {
        //freopen("test.txt","r",stdin);
        int ca,i,j,k,ans,t,flag,r;
        scanf("%d",&ca);
        while(ca--)
        {
            memset(a,0,sizeof(a));
            scanf("%d%d",&p,&n);
            for(i=0;i<n;i++)
                for(j=0;j<p;j++)
                {
                    scanf("%d",&t);
                    a[i]=a[i]*2+t;
                }
            ans=15;
            for(i=0;i<(1<<p);i++)
            {
                flag=0;
                s.clear();
                for(j=0;j<n;j++)
                {
                    t=i&a[j];
                    if(s.find(t)!=s.end()) {flag=1;break;}
                    s.insert(t);
                }
                if(!flag)
                {
                    r=0;
                    for(k=0;k<p;k++)
                        if(i&(1<<k)) r++;
                    if(r<ans) ans=r;
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Jquery消息提示插件toastr使用详解
    spingboot jar 包启动遇到得坑
    freemarker使用shiro标签(spring boot)
    sping boot 集成shiro
    java 线程安全(初级)
    java GC jvm 内存分布 和新生代,老年代,永久代,(详细)
    java的新生代 老年代 永久代
    windows下rabbitmq(架构师必备神器)集群搭建
    友盟移动开发平台.NET版本SDK
    jstree无限级菜单ajax按需动态加载子节点
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/4121877.html
Copyright © 2020-2023  润新知