三个题目讲解枚举(Packets、熄灯问题、称硬币Counterfeit Dollar)

目录

Packets

熄灯问题

称硬币Counterfeit Dollar 


枚举,是一种列出所有可能的情况,然后逐个检查是否是问题的解的解题方法;

下面以三道题目来讲解枚举方法;

Packets

大致题意:有6*6的大箱子和1*1 2*2 3*3 4*4 5*5 6*6的木块若干,高度均为h,输入每种箱子的数量,求出最小需要多少个大箱子。

分析:越大的物体越不灵活,从大向小分析。

1.6*6的木块需要一个箱子

2.5*5的木块可以剩下11个1*1木块的空间

3.4*4的木块可以剩下5个2*2的木块的空间

4.3*3的木块四个可占满,所有需要列举四种情况:

5.全部占满正好,空出来一个可以放1个2*2和5个1*1;空出来两个可以放3个2*2和6个1*1;空出来3个可以放5个2*2和7个1*1;

经过分析(a[i]表示i*i的木块个数)可以得出:

3*3需要(a[3]+3)/4个箱子(1-4个3*3需要一个箱子 5-8个需要2个推出需要+3)

那么多出来的2*2的有x=5*a[4]+u[a[3]%4]; u[4]={0,5,3,1};

多出来的1*1的有y=11*a[5]+v[a[3]%4];v[4]={0,7,6,5}

代码如下:

#include<algorithm>

#include<iostream>

#include<cstring>

#include<cstdio>

#include<cmath>

#include<stdlib.h>

using namespace std;

int main(){

         int a[10];

         int u[4] = {0,5,3,1};//u,v是针对于3*3能剩下的空间所开的数组 便于计算可装载1*1 2*2的 //个数

         int v[4] = {0,7,6,5};

         for(;;){

                  memset(a,0,sizeof(a));

                  int flag = 0;

                  for(int i = 1;i <= 6;i++){

                          cin >> a[i];

                          if(a[i] != 0) flag = 1;

                  }

                  if(flag == 0) break;

                  int ans = 0;

                  ans += (a[6]+a[5]+a[4]+(a[3]+3)/4);

                  int x =  5*a[4]+u[a[3]%4];//2*2;

                  int y = 11*a[5] + v[a[3]%4];//1*1;

                  if(x < a[2]){//先判断大的,如果发现2*2有多的 这是就要加上多出来的/9(1个箱 //子可装9个2*2)

                          int i = (a[2]-x+8)/9;

                          ans += i;

                          y += 4*(i*9-(a[2]-x));//多加箱子的话 1*1的也可能会多出来空间装 如 //果2*2装不满的话

                  }

                  else y += (x-a[2])*4;//发现2*2比预测可插空的少  那就留给1*1的 不要忘记!!

                  if(y < a[1]){

                          ans += (a[1]-y+35)/36; //判断1*1不够插空的话 就加箱子

                  }

                  cout << ans << endl;

         }

         return 0;

}

熄灯问题

大致题意是在5*6的格子里,每个格子里有盏灯,输入初始的亮灭情况,在一个格子里按按钮,那么本身以及上下左右五个灯亮的就熄灭,熄灭的就会变亮,问如何才能全灭,输出是否按按钮的5*6矩阵,按标1,不按标0;

这个题目如何枚举,如果dfs深搜会超时,情况太多。既然只有一种办法能让它全部熄灭,那么不妨枚举第一行的情况,第二行熄灭第一行亮的灯,以此类推,那么必定有一种情况让最后一行灯恰好全灭。

代码如下:

#include<cstdio>

#include<algorithm>

#include<iostream>

#include<stdlib.h>

#include<iostream>

#include<string.h>

#include<math.h>

#include <map>

#include <string>

using namespace std;

typedef long long ll;

int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};

int sta[10][10];

int press[10][10];

int ini[10][10];

void reverse_sta(int x,int y){//写下每次按按钮会改变的灯的状况

       for(int i = 0;i < 4;i++){

              int xx = x+dir[i][0];

              int yy = y+dir[i][1];

              if(xx < 0||yy < 0||xx > 4||yy > 5) continue;

              if(sta[xx][yy] == 1) sta[xx][yy] = 0;

              else sta[xx][yy] = 1;

       }

       if(sta[x][y] == 1) sta[x][y] = 0;//不要忘记本身更改状态

       else sta[x][y] = 1;

}

bool check(){//检查最后一行是否恰好全部熄灭

       for(int i = 0;i < 6;i++)

              if(sta[4][i] == 1 ) return false;

       return true;

}

void copy(){

       for(int i = 0;i < 5;i++)

              for(int j = 0;j < 6;j++)

                     sta[i][j] = ini[i][j];

}

int main(){

       for(int i = 0;i < 5;i++)

              for(int j = 0;j < 6;j++)

                     cin >> ini[i][j];

       for(int s = 1 << 5 ; s <= 95;s++){//枚举0000001-1000000 其实与0-64一样 只不过枚举的 //顺序不一样

              memset(press,0,sizeof(press));//每次都需要初始化press按钮的按键情况

              copy();//重置初始灯状态

              for(int i = 0;i < 6;i++){

                     if((s>>i)&1){//只能枚举第一行按不按 无法枚举亮灭状态 因为无法判断第一行 //怎么按按钮能从初始状态到枚举状态

                            reverse_sta(0,i);

                            press[0][i] = 1;

                     }

              }

              for(int i = 1;i < 5;i++){

                     for(int j = 0;j < 6;j++){

                            if(sta[i-1][j] == 1){

                                   reverse_sta(i,j);

                                   press[i][j] = 1;

                            }

                     }

              }

              if(check()){

                     for(int i = 0;i < 5;i++){

                            for(int j = 0;j < 6;j++){

                                   cout << press[i][j] << " ";

                            }

                            cout << endl;

                     }

              }

             

              }

      

       return 0;

}

称硬币Counterfeit Dollar 

有12枚硬币,代号为A——L,其中有一枚假的,唯一区别就是假币重量和真币不一样,真币重量都是一样的,称量三次,给出了称量方法和结果,问哪一枚是假的,并且输出比真币轻还是重

不是问的称重办法 让你判断哪一枚是假的,那么你就假设这一门是假的,看它符合不符合称重情况。显然,枚举每一个硬币,假设是假的 还要假设重还是轻 满足就输出

代码如下:

#include<iostream>

#include<algorithm>

#include<string.h>

using namespace std;

char lefts[3][10];

char rights[3][10];

char results[3][10];

bool exist(char c,char s[3][10],int x){//判断这个字符是否在s数组中

       for(int i = 0;i < strlen(s[x]);i++)

              if(s[x][i] == c) return true;

       return false;

}

bool isfake(char c,int f){//判断c是假币的话出现什么情况应该false 假设都避开了 那就true 也就 
  //确认是假币了

       for(int i = 0;i < 3;i++){ //不可以忽略不在称上的时候的情况

              if(f == 1){//轻

                     switch(results[i][0]){

                            case 'u': if(!exist(c,rights,i)) return false;

                                   break;

// 如果c不在右边 那么肯定不会天平右边轻-升高,所以false,不可以判断如果在左边就错误,可能没有被 
 //称重

                            case 'd': if(!exist(c,lefts,i)) return false;             

                                   break;

// 如果c不在左边 那么肯定不会天平右边重-下降,所以false,不可以判断如果在右边就错误,可能没有被 
 //称重     

                            case 'e':if(exist(c,rights,i) || exist(c,lefts,i)) return false;

                                   break;

//不论c在哪一边 只要是在天平上 如果是假币 就不会出现平衡状态 也就是出现在任何一方 就false

                    }    

              }

              else if(f == 0){//重

                     switch(results[i][0]){

                            case 'u': if(!exist(c,lefts,i)) return false;

                                   break;

//如果c不在左边 那么肯定不会出现右边轻-高的情况,false

                            case 'd': if(!exist(c,rights,i)) return false;

                                   break;

//如果c不在右边 那么肯定不会出现右边重-低的情况,false

                            case 'e': if(exist(c,rights,i) || exist(c,lefts,i)) return false;

                                   break;

//不论c在哪一边 只要是在天平上 如果是假币 就不会出现平衡状态   也就是出现在任何一方 就false

                    }                         

              }

       }

       return true;

}

int main(){

       int n;

       cin >> n;

       while(n--){

              for(int i = 0;i < 3;i++)

                     cin >> lefts[i] >> rights[i] >> results[i];// up down针对于右边 轻者高

              for(char c = 'A';c <= 'L';c++){

                     if(isfake(c,1)){

                            printf("%c is the counterfeit coin and it is light.\n",c); break;//注意换行符-输出格式

                     }

                     else if(isfake(c,0)){

                            printf("%c is the counterfeit coin and it is heavy.\n",c);break;

                     }

              }

       }    

       return 0;

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个问题通常是由于数据库连接超时或者连接被关闭导致的。解决方案如下: 1. 检查数据库连接是否正常,可以使用ping命令测试数据库服务器是否可达。 2. 检查数据库连接是否超时,可以在连接字符串中设置连接超时时间。 3. 检查数据库连接池是否正确配置,如果连接池配置不正确,可能会导致连接被回收。 4. 检查数据库服务器是否正常运行,如果数据库服务器出现故障,可能会导致连接失败。 解决方案1:检查数据库连接是否正常,可以使用ping命令测试数据库服务器是否可达。 ```shell ping <数据库服务器IP地址> ``` 解决方案2:在连接字符串中设置连接超时时间。 ```python import mysql.connector config = { 'user': 'root', 'password': 'password', 'host': '127.0.0.1', 'database': 'test', 'raise_on_warnings': True, 'connect_timeout': 10 # 设置连接超时时间为10秒 } cnx = mysql.connector.connect(**config) ``` 解决方案3:检查数据库连接池是否正确配置,如果连接池配置不正确,可能会导致连接被回收。 ```python import mysql.connector.pooling config = { 'user': 'root', 'password': 'password', 'host': '127.0.0.1', 'database': 'test', 'raise_on_warnings': True, 'pool_name': 'example_pool', 'pool_size': 5, # 设置连接池大小为5 'pool_reset_session': True # 每次从连接池中获取连接时,都会重置会话状态 } cnxpool = mysql.connector.pooling.MySQLConnectionPool(**config) cnx = cnxpool.get_connection() ``` 解决方案4:检查数据库服务器是否正常运行,如果数据库服务器出现故障,可能会导致连接失败。 ```shell systemctl status mysql ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值