• 蓝桥杯(受约束的10人参赛问题)


    A、B、C、D、E、F、G、H、I、J 共10名学生有可能参加本次计算机竞赛,也可能不参加。

    因为某种原因,他们是否参赛受到下列条件的约束:

       1. 如果A参加,B也参加;

       2. 如果C不参加,D也不参加;

       3. A和C中只能有一个人参加;

       4. B和D中有且仅有一个人参加;

       5. D、E、F、G、H 中至少有2人参加;

       6. C和G或者都参加,或者都不参加;

       7. C、E、G、I中至多只能2人参加  

       8. 如果E参加,那么F和G也都参加。

       9. 如果F参加,G、H就不能参加

       10. 如果I、J都不参加,H必须参加

    请编程根据这些条件判断这10名同学中参赛者名单。如果有多种可能,则输出所有的可能

    情况。每种情况占一行。参赛同学按字母升序排列,用空格分隔。

    比如:

    C D G J

    就是一种可能的情况。

     1 //该题的关键还在于如何枚举10个数,可以10重for循环,也可以类似素数环进行回溯,或者二进制枚举 
     2 #include <iostream>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 int vis[11] = {0};
     7 
     8 //vis若是bool 变不可写成两数相加减 
     9 bool judge()
    10 {
    11      //a推出(蕴含)b,等价于(非a或b);或者a ==1&&b==1||a==0,等价于a==0||b==1,此次用到了短路表达式的性质 
    12      bool t1 = (vis[0]== 0||vis[1] == 1);
    13      //类似第一个;或者c==0&&d==0||c=1 
    14      bool t2 =( vis[2] == 1||vis[3] == 0);
    15      //从第四个条件可以看出这个包含都不参加的情况,等价于都不参加或者只参加一个人,反面是两个人都参加,再取反 !(a==1&&c==1)等价于a==0||c==0,转化为a+c<=1
    16      bool t3 = ((vis[0] + vis[2])<=1);//或者等于0 
    17      //反面是同时参加或者同时不参加,再取反!(b==d),等价于b+d ==1
    18      bool t4 = (vis[1] + vis[3]==1);
    19      bool t5 = ((vis[3] + vis[4] + vis[5] + vis[6] + vis[7]) >=2);
    20      //c==g,可化为就、相加为0或者2 
    21      bool t6 = (vis[2] == vis[6]);
    22      bool t7 = ((vis[2]+vis[4]+vis[6]+vis[8])<=2);
    23      //类似第一个 
    24      bool t8 = (vis[4] == 0||(vis[5] + vis[6] == 2));
    25      bool t9 = vis[5]==0||(vis[6]+vis[7]==0);
    26      //(i ==0&&j==0)&&h==1||(ij至少一人参加),等价于(i==1||j==1)||h==1 
    27      bool t10 = (vis[8]+vis[9]>0)||vis[7]==1;
    28      return t1&&t2&&t3&&t4&&t5&&t6&&t7&&t8&&t9&&t10;
    29 }
    30 void print()
    31 {
    32      int i,j,k;
    33      for(i=0; i<10; i++)
    34           if(vis[i]>0)//若vis是bool,所以不可写成vis[i]>0 
    35           {
    36                char ch = i + 'A';
    37                cout<<ch<<" ";
    38           }
    39 }
    40 int main()
    41 {
    42      int i,j,k;
    43      //二进制枚举比递归回溯好理解 
    44      //二进制枚举,两数的与或疑惑分别表示集合的交并对称差 
    45      int total = 0;//
    46      memset(vis,0,sizeof(vis));
    47      while(total<1024)//用total的前十位表示参加状态,1024并不是来自1<<10,而是十个1表示(1<<10-1) 
    48      {
    49           total++;//不可能全都不参加,所以先自增了
    50           for(i=0; i<10; i++)//用total的底10为表示状态,或者total按求余法求的底十位 
    51           {
    52                int temp = (1<<i);
    53                int tag = (temp & total);
                // 也可以用临时变量先存储total,然后total每次右移,与1求与,刘汝佳课本上不是这种方法 
    54 if(tag) 55 { 56 //cout<<"*******"<<endl; 57 vis[i] = 1;//把赋值号写成了等号 58 } 59 else 60 vis[i] = 0; 61 } 62 bool flag = judge(); 63 //cout<<flag<<endl; 64 if(flag) 65 { 66 print(); 67 cout<<endl; 68 } 69 } 70 cout<<"----"<<endl; //结果没输出,看看是否执行到了这一步 71 cout<<endl; 72 while(1); 73 return 0; 74 } 75 //把给的例子带入发现正确,说明judge函数没问题,那么就是while循环有问题了 ,结果发现vis全为0 ,再以发现把赋值号写成了等号 76 77
     1 //递归回溯 
     2 #include <iostream>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 int vis[11] = {0};
     7 
     8 //vis若是bool 变不可写成两数相加减 
     9 bool judge()
    10 {
    11      //a推出(蕴含)b,等价于(非a或b);或者a ==1&&b==1||a==0,等价于a==0||b==1,此次用到了短路表达式的性质 
    12      bool t1 = (vis[0]== 0||vis[1] == 1);
    13      //类似第一个;或者c==0&&d==0||c=1 
    14      bool t2 =( vis[2] == 1||vis[3] == 0);
    15      //从第四个条件可以看出这个包含都不参加的情况,等价于都不参加或者只参加一个人,反面是两个人都参加,再取反 !(a==1&&c==1)等价于a==0||c==0,转化为a+c<=1
    16      bool t3 = ((vis[0] + vis[2])<=1);//或者等于0 
    17      //反面是同时参加或者同时不参加,再取反!(b==d),等价于b+d ==1
    18      bool t4 = (vis[1] + vis[3]==1);
    19      bool t5 = ((vis[3] + vis[4] + vis[5] + vis[6] + vis[7]) >=2);
    20      //c==g,可化为就、相加为0或者2 
    21      bool t6 = (vis[2] == vis[6]);
    22      bool t7 = ((vis[2]+vis[4]+vis[6]+vis[8])<=2);
    23      //类似第一个 
    24      bool t8 = (vis[4] == 0||(vis[5] + vis[6] == 2));
    25      bool t9 = vis[5]==0||(vis[6]+vis[7]==0);
    26      //(i ==0&&j==0)&&h==1||(ij至少一人参加),等价于(i==1||j==1)||h==1 
    27      bool t10 = (vis[8]+vis[9]>0)||vis[7]==1;
    28      return t1&&t2&&t3&&t4&&t5&&t6&&t7&&t8&&t9&&t10;
    29 }
    30 
    31 void print()
    32 {
    33      int i,j,k;
    34      for(i=0; i<10; i++)
    35           if(vis[i]>0)//若vis是bool,所以不可写成vis[i]>0 
    36           {
    37                char ch = i + 'A';
    38                cout<<ch<<" ";
    39           }
    40 }
    41 
    42 void dfs(int n)
    43 {
    44      if(n>=10)
    45      {
    46           if(judge())
    47           {
    48                print();
    49                cout<<endl;
    50           }
    51           return ;
    52      }
    53      vis[n] = 0;
    54      dfs(n+1);
    55      vis[n] = 1;
    56      dfs(n+1);
    57 }
    58 
    59 int main()
    60 {
    61      int i,j,k;
    62      int total = 0;//
    63      memset(vis,0,sizeof(vis));
    64      dfs(0);
    65      cout<<"----"<<endl; //结果没输出,看看是否执行到了这一步      
    66      cout<<endl;
    67      while(1);
    68      return 0;
    69 }
    70 //把给的例子带入发现正确,说明judge函数没问题,那么就是while循环有问题了 ,结果发现vis全为0 ,再以发现把赋值号写成了等号 
    71      
    72      


    看视频加上写代码和注释共约4个小时,还是相当有成就感的。

  • 相关阅读:
    jQuery.extend()
    reconnecting-websocket.js
    网页防止嵌套
    mysql 一张表的多个字段关联另外一张表
    php把一些预定义的 HTML 实体转换为字符。
    weex用阿里矢量图
    nodeJS有多快
    关于jquery中prev()和next()的用法
    关于手动添加属性的方法总结
    关于一个div上下左右居中的css方法
  • 原文地址:https://www.cnblogs.com/hxsyl/p/2819492.html
Copyright © 2020-2023  润新知