• 算法基础_枚举


    枚举:基于逐个尝试答案的一种问题求解策略


     1. 完美立方

    题目描述:

    形如a^3= b^3 + c^3 + d^3的等式被称为完美立方等式。例如
    12^3= 6^3 + 8^3 + 10^3 。编写一个程序,对任给的正整数N
    (N≤100),寻找所有的四元组(a, b, c, d),使得a^3 = b^3 +
    c^3 + d^3,其中a,b,c,d 大于1 , 小于等于N,且b<=c<=d。
    输入
    一个正整数N (N≤100)。
    输出
    每行输出一个完美立方。输出格式为:
    Cube = a, Triple = (b,c,d)
    其中a,b,c,d所在位置分别用实际求出四元组值代入。
    要求a从小到大输出。  

    解题思路:

    四重循环枚举a,b,c,d
    a在最外层,d在最里层,每一层都是从小到大枚举,
    a 范围 [2, N]
    b 范围 [2, a-1]
    c 范围 [b, a-1]
    d 范围 [c, a-1]
    

    代码示例:

    // 完美立方
    # include <stdio.h> 
    
    int main(void)
    {
    	int a,b,c,d;
    	int N;
    	scanf("%d",&N);
    	
    	for (a=2; a<=N; a++)
    		for (b=2; b<=a-1; b++)
    			for (c=b; c<=a-1; c++)
    				for (d=c; d<=a-1; d++)
    					if (a*a*a == b*b*b + c*c*c + d*d*d)
    						printf("Cube = %d, Triple = (%d,%d,%d)
    ",a,b,c,d);
    	
    	return 0;
    }
    

    2. 生理周期

    题目描述:

    人生来就有三个生理周期,分别为体力、感情和智力周期, 它们的周期长度为23天、28天和33天。每一个周期中有一天 是高峰。在高峰这天,人会在相应的方面表现出色。 例如,智力周期的高峰,人会思维敏捷,精力容易高度集中。 因为三个周期的周长不同,所以通常三个周期的高峰不会落在 同一天。对于每个人,我们想知道何时三个高峰落在同一天。 对于每个周期,我们会给出从当前年份的第一天开始, 到出现高峰的天数(不一定是第一次高峰出现的时间)。
     你的任务是给定一个从当年第一天开始数的天数, 输出从给定时间开始(不包括给定时间)下一次三个高峰
     落在同一天的时间(距给定时间的天数)。
     例如:给定时间为10,下次出现三个高峰同天的时间是12, 则输出2(注意这里不是3)。输入有多组数据,以一行-1结束。
    

    解题思路:

    从第d+1天开始, 一直试到第21252天,对其中每一天看是否满足
    当前日期与 p e i差值分别能被 23 28 33 同时整除
    

    代码示例:

    // 生理周期 
    # include <iostream>
    using namespace std;
    
    int main(void)
    {
    	int p,e,i,d,j, num=0;
    	// 没必要全部枚举 
    	while (cin>>p>>e>>i>>d && p!=-1)
    	{
    		++num;
    		for (j=d+1; (j-p)%23; j++); // 先找到第一个是23倍数的日期 
    		for (     ; (j-e)%28; j+=23); // 再按照23的增量查看是否是28的倍数 
    		for (     ; (j-i)%33; j+=23*28); // 最后再以23*28的增量确定是否是33 的倍数 
    		cout<<"Case"<<num<<": the next triple peak occours in";
    		cout<<j-d<<"days"<<endl; // 最后输出 j d 之间的间隔  
    	}
    	
    	return 0;
     } 
    

    3. 称硬币

    问题描述:

    有12枚硬币,其中有11枚真币和1枚假币。
    假币和真币重量不同,但不知道假币比真币轻还是重。
    现在,用一架天平称了这些币三次,告诉你称的结果,
    请你找出假币并且确定假币是轻还是重。
    
    输入样例:
    1
    ABCD EFGH even  //天平左边是ABCD四枚,右边是EFGH,平衡。
    ABCI EFJK up  //右边翘起来
    ABIJ EFGH even  //相同
    //表示的都是右边重量
    

    解题思路:

    		对于每一枚硬币先假设它是轻的,看是否符合称量结果。
    		如果符合,则问题解决。否则,假设他是重的,看是否
    		符合称量结果。把所有硬币都试一遍,一定能找到特殊硬币。
    

    代码示例:

    // 称硬币
    # include <iostream>
    # include <cstring> 
    using namespace std;
    char Left[3][7]; // 天平左边硬币 
    char Right[3][7]; // 天平右边硬币 
    char result[3][7]; // 结果 
    bool IsFake(char c, bool light);
    
    int main(void)
    {
    	int t; 
    	cin>>t;
    	while(t--)
    	{
    		for (int i = 0; i<3; i++)
    			cin>>Left[i]>>Right[i]>>result[i];
    		for (char c='A'; c<='L'; c++)
    		{
    			if (IsFake(c, true))
    			{
    				cout<<c<<" is the counterfeit coin and it is light.
    ";
    				break;
    			}
    			else if(IsFake(c, false))
    			{
    				cout<<c<<" is the counterfeit coin and it is heavy.
    ";
    				break;
    			}
    		}
    	}
    	return 0;
    }
    
    bool IsFake(char c, bool light)
    // light 为真表示假设假币为轻,否则假币为重 
    {
    	for (int i=0; i<3; i++)
    	{
    		char * pLeft,*pRight; // 指向天平两边的字符串
    		if (light)
    		{
    			pLeft = Left[i];
    			pRight = Right[i];
    		}
    		else // 如果假设是重的,则把天平结果左右对换 
    		{
    			pLeft = Right[i];
    			pRight = Left[i];
    		} 
    		
    		switch(result[i][0]) // 天平右边的情况 
    		{
    			case 'u': if(strchr(pRight,c) == NULL)
    						return false;
    					  break;
    			case 'e': if(strchr(pLeft,c) || strchr(pRight,c))
    						return false;
    					  break;
    			case 'd': if(strchr(pLeft,c) == NULL)
    						return false;
    					  break;
    		}
    		 
    	} 
    	return true;
    } 
    

    4. 熄灯问题 

    部分内容转自 https://blog.csdn.net/NNNNNNNNNNNNY/article/details/51584247 

     问题分析:

    上述解析代码示例:(便于理解)

    // 熄灯问题_02_plus 
    #include <stdio.h>
    
    int puzzle[6][8], press[6][8];
    /*
    推测验证过程:
    根据第一行猜测
    */
    bool guess() {
        int c, r;
        //根据press第1行和puzzle数组,计算press其他行的值
        for(r=1; r<5; r++) {
            for(c=1; c<7; c++) {
                press[r+1][c]=(puzzle[r][c]+press[r][c]+press[r-1][c]+press[r][c-1]+press[r][c+1])%2;
            }
        }
        //判断所计算的press数组能否熄灭第5行的所有灯
        for(c=1; c<7; c++) {
            if ((press[5][c-1]+press[5][c]+press[5][c+1]+press[4][c])%2 != puzzle[5][c]) {
                return false;
            }
        }
        return true;
    }
    
    /*
    枚举过程:
    对press第1行的元素press[1][1]~press[1][6]的各种取值进行枚举
    */
    void enumerate() {
        int c;
        bool success; //这个变量时当时定义了没排上用场吧,NodYoung注
        for(c=1; c<7; c++) {
            press[1][c]=0;
        }
        while(guess()==false) {
            press[1][1]++;
            c=1;
            while(press[1][c]>1) {  //累加进位
                press[1][c]=0;
                c++;
                press[1][c]++;
            }
        }
        return ;
    }
    
    int main() {
        int cases, i, r, c;
        scanf("%d", &cases);
        for(r=0; r<6; r++) {
            press[r][0]=press[r][7]=0;
        }
        for(c=0; c<7; c++) {
            press[0][c]=0;
        }
        for(i=0; i<cases; i++) {
            for(r=1; r<6; r++) {
                for(c=1; c<7; c++) {
                    scanf("%d", &puzzle[r][c]); //读入输入数据
                }
            }
            enumerate();
            printf("PUZZLE#%d
    ", i+1);
            for (r=1; r<6; r++) {
                for (c=1; c<7; c++) {
                    printf("%d ", press[r][c]);
                }
                printf("
    ");
            }
        }
        return 0;
    }

    老师给出的另一种代码示例:

    // 熄灯问题_03_plus 
    #include <memory>
    #include <string>
    #include <cstring>
    #include <iostream>
    using namespace std;
    int GetBit(char c,int i) {
    	//取c的第i位
    	return ( c >> i ) & 1;
    }
    void SetBit(char & c,int i, int v) {
    	//设置c的第i位为v
    	if( v )
    		c |= ( 1 << i);
    	else
    		c &= ~( 1 << i);
    }
    void Flip(char & c, int i) {
    	//将c的第i位为取反
    	c ^= ( 1 << i);
    }
    void OutputResult(int t,char result[]) //输出结果
    {
    	cout << "PUZZLE #" << t << endl;
    	for( int i = 0;i < 5; ++i ) {
    		for( int j = 0; j < 6; ++j ) {
    			cout << GetBit(result[i],j);
    				if( j < 5 )
    					cout << " ";
    		}
    		cout << endl;
    	}
    }
    int main() {
    	char oriLights[5]; //最初灯矩阵,一个比特表示一盏灯
    	char lights[5]; //不停变化的灯矩阵
    	char result[5]; //结果开关矩阵
    	char switchs; //某一行的开关状态
    	int T;
    	cin >> T;
    	for( int t = 1; t <= T; ++ t) {
    		memset(oriLights,0,sizeof(oriLights));
    		for( int i = 0;i < 5; i ++ ) { //读入最初灯状态
    			for( int j = 0; j < 6; j ++ ) {
    				int s;
    				cin >> s;
    				SetBit(oriLights[i],j,s);
    			}
    		}	
    		for( int n = 0; n < 64; ++n ) { //遍历首行开关的64种状态
    			memcpy(lights,oriLights,sizeof(oriLights));
    			switchs = n; //第i行的开关状态
    			for( int i = 0;i < 5; ++i ) {
    				result[i] = switchs; //第i行的开关方案
    				for( int j = 0; j < 6; ++j ) {
    					if( GetBit(switchs,j)) {
    						if( j > 0)
    							Flip(lights[i],j-1);//改左灯
    						Flip(lights[i],j);//改开关位置的灯
    						if( j < 5 )
    							Flip(lights[i],j+1);//改右灯
    					}		
    				}
    				if( i < 4 )
    					lights[i+1] ^= switchs;//改下一行的灯
    				switchs = lights[i]; //第i+1行开关方案和第i行灯情况同
    			}	
    			if( lights[4] == 0 ) {
    				OutputResult(t,result);
    				break;
    			}
    		} // for( int n = 0; n < 64; n ++ )
    	}
    	return 0;
    }
    

    RRR

    本人计算机小白一枚,对编程有浓厚兴趣,在此贴出自己的计算机学习历程,还有很多不足,望多多指教! 读书后发现好多的内容与具体专业有偏差,没来得及完成,虽然“有时间我就会做...”是人生最大的谎言,但有时间我会继续搞定未完成的内容,有始有终,兴趣使然!
  • 相关阅读:
    AVUE 根据 某个字段 倒序查询
    Java hutool工具包的使用
    AVUE 添加搜索项
    SpringBlade 添加 回收站功能
    接口 form-data 将对象转换为复杂url参数
    AVUE 隐藏 新增按钮
    AVUE 查看crud列的属性配置
    AVUE dialog对话框 去掉 点击屏幕空白区 就关闭弹框
    接口 C#/Java 请求数据 raw 的方式传输复杂对象
    接口 PostMan 常用
  • 原文地址:https://www.cnblogs.com/Robin5/p/11235208.html
Copyright © 2020-2023  润新知