• 子集生成——增量构造法+位向量法+二进制法


    增量构造法:

    原理图:

              

     1 // 此算法仅用于输出下标,实际运用应输入另一个数组来进行数据的储存
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 typedef long long ll;
     5 typedef unsigned long long ull;
     6 #define INF 0X3f3f3f3f
     7 const ll MAXN = 1e3 + 7;
     8 const ll MOD = 1e9 + 7;
     9 int a[10];
    10 void print_subset(int n,int cur)//cur相当于遍历图的层数
    11 {
    12     for(int i=0;i<cur;i++) cout<<a[i];
    13     cout<<endl;
    14     // 找到当前子集的第一个元素
    15     int s=cur?a[cur-1]+1:0;//确定当前元素的最小可能值
    16     /* 这一句很难懂,实际上就是相当于下面的代码
    17     int s;
    18     if(cur==0) s=0;
    19     else s=a[cur-1];
    20      */
    21     for(int i=s;i<n;i++)
    22     {
    23         a[cur]=i;
    24         //当前层子集第一个值
    25         //cur+1表示当前层值设置完毕,开始递归下一层,和前面步骤一样。
    26         //到达最后一层结束后return 到上一层,然后i++,a[cur]的值(首元素)改变,又反复递归下一层
    27         print_subset(n,cur+1);
    28     }
    29     return ;
    30 }
    31 int main()
    32 {
    33     print_subset(4,0);
    34     system("pause");
    35     return 0;
    36 }

    位向量法:

    构造一个位向量,而不是直接构造子集本身

    位向量的解答树如图:

                     

     1 // 此算法仅用于输出下标,实际运用应输入另一个数组来进行数据的储存
     2 // 在枚举子集的位向量法中,解答树的结点掠夺,但在多数情况下仍然够快
     3 #include <bits/stdc++.h>
     4 using namespace std;
     5 typedef long long ll;
     6 typedef unsigned long long ull;
     7 #define INF 0X3f3f3f3f
     8 const ll MAXN = 1e3 + 7;
     9 const ll MOD = 1e9 + 7;
    10 int a[10];
    11 void print_subset(int n, int cur)
    12 {
    13     if (cur == n)
    14     {
    15         for (int i = 0; i < cur; i++)
    16             if (a[i]) cout << i;
    17         cout << endl;
    18         return;
    19     }
    20     a[cur]=1;//选第cur个元素
    21     print_subset(n,cur+1);
    22     a[cur]=0;//不选第cur个元素
    23     print_subset(n,cur+1);
    24 }
    25 int main()
    26 {
    27     print_subset(4, 0);
    28     // system("pause");
    29     return 0;
    30 }

    二进制法:

    还可以用二进制来表示{0,1,2······,n-1}的子集S:从右往左第i位(各位从0开始编号)表示i是否在集合S中,图中展示了二进制0100011000110111是如何表示集合{0,1,2,4,5,9,10,14}的

                                   

     1 //此算法仅仅是输出下标,实际应用应输入另一个数组来进行存储数据
     2 //原理:用数字的二进制位表示状态,二进制从右到左的第几个位置 表示数组元素的下标
     3 #include <bits/stdc++.h>
     4 using namespace std;
     5 typedef long long ll;
     6 typedef unsigned long long ull;
     7 #define INF 0X3f3f3f3f
     8 const ll MAXN = 1e3 + 7;
     9 const ll MOD = 1e9 + 7;
    10 void print_subset(int n, int s) 
    11 {
    12     //s代表的是当前二进制数表示的状态
    13     for(int i = 0; i < n; ++i) 
    14         if(s & (1 << i)) //1右移几位就代表第i个二进制位为1,其他位为0,与状态进行&运算,如果此状态包含该数字,就输出
    15             cout<<i;
    16     cout<<endl;
    17 }
    18 int main() 
    19 {
    20     int n;
    21     while(cin>>n) 
    22     {
    23         //一共n个数字,所以其全集有2^n个二进制1,所对应的十进制数字就是2^n - 1
    24         //我们要做的就是枚举出来每一种状态,1 右移 n 位,所得的十进制数字就是2^n
    25         for(int i = 0; i < (1 << n) ; ++i)       //i表示集合元素的状态,根据该状态打印出当前集合
    26             print_subset(n, i);
    27     }
    28     return 0;
    29 }
  • 相关阅读:
    android关闭屏幕时不锁屏实现
    android Seekbar 拖动按钮显示不全问题
    webview在compileSdkVersion 大于等于23 android6.0以上系统执行js代码异常,但是在compileSdkVersion小于23 android6.0以下系统却执行正常问题
    Seekbar扩大点击区域
    android .9背景图作为TextView背景时文字无法居中问题
    android 使用系统级别权限
    自定义ViewPager,避免左右滑动时与水平滑动控件冲突
    ListVIew中包含水平滑动控件,左右滑动时容易触发上下滑动
    Android输入法挤乱布局问题
    android WebView缩放时卡顿问题
  • 原文地址:https://www.cnblogs.com/graytido/p/10464365.html
Copyright © 2020-2023  润新知