算法课-暴力搜索
暴力搜索
课堂例题
啤酒和饮料
1 /* 2 * 啤酒每罐2.3元,饮料每罐1.9元。 3 * 小明买了若干啤酒和饮料,一共花了82.3元。 4 我们还知道他买的啤酒比饮料的数量少, 5 请你计算他买了几罐啤酒。 6 */ 7 //百钱百鸡类问题 8 9 #include<stdio.h> 10 int main() 11 { 12 int beer = 0 ; 13 int drink = 0 ; 14 int Money ; 15 //技巧1:直接穷举啤酒数量. 16 //通过计算剩余的钱能购买多少瓶饮料?满足题目要求的数量上"啤酒<饮料" 17 for( beer = 1 ; ; beer ++ ){ 18 //技巧2:小数不好计算把问题中所有的数目乘以十倍 19 20 //计算剩余的钱 21 Money = 823 - beer * 23 ; 22 23 //剩余的钱只能购买整数倍的饮料 24 if( Money % 19 == 0 ){ 25 drink = Money / 19 ; 26 27 // "啤酒<饮料" 28 if( beer < drink ){ 29 printf("beer : %d , drink %d\n",beer,drink); 30 break; 31 } 32 } 33 } 34 return 0; 35 }
勾股定理
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6441
来源:ccpc2018网络赛D题
给定a和n,问是否存在b,c
如果存在b,c请输出其中一组答案
如果不存在请输出“-1,-1”
【解析】
分类讨论:
n = 1 : b = 1 , c = a + 1
n = 0 或 n >= 3 (费马大定理) :不存在 b = c = -1
n = 2 :
公式推导加构造
a 为奇数时:
a 为偶数时:
1 #include<cstdio> 2 using namespace std; 3 typedef long long ll; 4 5 int main() 6 { 7 int T ; 8 scanf("%d",&T); 9 while( T-- ){ 10 int n , a ; 11 scanf("%d%d",&n,&a); 12 if( n == 1 ){ 13 printf("%d %d\n",1,a+1); 14 }else if( n == 0 || n >= 3 ){ 15 printf("-1 -1\n"); 16 }else if( a == 1 && n == 2 ){ 17 printf("-1 -1\n"); 18 }else if( n == 2 ){ 19 if( a % 2 == 1 ){ 20 printf("%d %d\n",(a*a-1)/2,(a*a+1)/2); 21 }else{ 22 printf("%d %d\n",(a*a-4)/4,(a*a+4)/4); 23 } 24 } 25 } 26 return 0 ; 27 }
蓝桥杯 颠倒的价牌
【题意】 {0,1,2,5,6,8,9}可颠倒,其中颠倒后只有 "6" -> "9" , "9" -> "6" ,其余数字没有变化。 价牌确保4位数 (即千位 上的数字不能为0) 例如 "1958" -> "8561" 有两个价牌进行翻转后,有一个比原来的数少了"200+",另一个数翻转后多了"800+" 问:然后将两者的 亏损 (”负两百多“) 和 盈利 (“正八百多”) 后的值加起来 刚好等于558 请问针对亏损的价牌:原来的价牌应该是多少?
【题解】 1、通过搜索枚举出每个位置上的数字 ,并确保千位上不能是0 枚举的过程中记录两个价牌的情况,即 数字进行颠倒后差值变化为-200多,和+800的情况 2、然后通过分别枚举刚才搜索出来的结果进行相加 判断其累加后的结果是否为558 然后输出把对应亏损价牌的原价牌。
【具体代码】
1 #include<stdio.h> 2 3 const int N = 2e3 ; 4 5 //p -> price 通过获取下标来填充 6 int p[] = { 0 , 1 , 2 , 5 , 6 , 8 , 9 }; 7 int Mp[] = { 0 , 1 , 2 , 5 , 9 , 8 , 6 }; 8 9 // D1 D2 -> difference 差值 ( 相差两百多 , 相差八百多 ) 10 // tot1 , tot2 -> 可能存在多组情况,记录个数 11 // 记录D1中,原价牌数值 12 int D1[N] , Price[N] , tot1 = 0 ; 13 int D2[N] , tot2 = 0 ; 14 15 int choose[4] ; 16 void dfs( int step ){ 17 18 if( step == 4 ){ 19 int A = 0 ; 20 int B = 0 ; 21 for (int i = 0 ; i < 4 ; i ++ ){ 22 A = A * 10 + p[choose[i]]; 23 } 24 for (int i = 3; i >=0 ; i -- ){ 25 B = B * 10 + Mp[choose[i]]; 26 } 27 28 if( -300 < A - B && A - B < -200 ){ 29 Price[tot1] = B ; 30 D1[tot1++] = A - B ; 31 } 32 if( 800 < A - B && A - B < 900 ){ 33 D2[tot2++] = A - B ; 34 } 35 return ; 36 } 37 // 首尾不能是'0' 38 for( int i = ( step == 0 || step == 3 ) ; i < 7 ; i ++ ){ 39 choose[step] = i; 40 dfs( step + 1 ); 41 } 42 } 43 int main() 44 { 45 dfs(0); 46 47 for( int i = 0 ; i < tot1 ; i ++ ){ 48 for( int j = 0 ; j < tot2 ; j ++ ){ 49 if( D1[i] + D2[j] == 558 ){ 50 printf("%d\n",Price[i]); 51 } 52 } 53 } 54 return 0; 55 }
子集和问题
【题意】
给定一个集合和一个正整数c,判定是否存在该集合的子集,使其所有元素的和等于给定的正整数c?
【题解】 暴力枚举每个位置是否为子集中的元素。通过{0,1}来表示, 如果该位置是"1",那么该位置上的元素被选中,则进行累加, 否则该位置是"0",该位置上的元素没被选中,不做任何处理。
【技巧】 1、如何枚举该位置上是否为0,1的所有情况? 答:通过移位运算获取所有情况 1 << n 左移运算 分析对于n个数来数,每个数字都有选和不选两种情况。 对于所有方案来说:共有 2^n for( i = 0 ; i < 1 << n ; i ++ ) 即可把所有情况给枚举出来,把 (1<<n) -> (2 ^ n) 例如:n = 3 则枚举 0 ~ (2^3 - 1) -> 0 ~ 7 通过二进制的转换后变成 000,001,010,011,100,101,110,111 2、如何判断该位置上是否为0或者1。 答:通过移位运算即可。 1 << n 右移运算 //枚举n个位置 for( j = 0 ; j < n ; j++ ){ //判断第j个位置上是否为1 if( (i >> j & 1) == 1 ){ }else{ } } 比如:判断"6" ->"110" 各位上的{0,1}情况 1、从右往左第一位 6 >> 0 & 1 = "110" & "001" = "000" = 0 2、从右往左第二位 6 >> 1 & 1 = " 11" & "001" = "001" = 1 3、从右往左第三位 6 >> 2 & 1 = " 1" & "001" = "001" = 1
1 #include<stdio.h> 2 int a[] = { 1 , 2 , 3 , 4 , 5 , 6 }; 3 int main() 4 { 5 int n ; 6 n = 6 ; 7 //枚举所有情况 8 for( int i = 1 ; i < 1 << 6 ; i ++ ){ 9 int tmp = 0 ; 10 //累加上 所有转化为二进制后的 '1' 的位置上对应的数 11 for( int j = 0 ; j < 6 ; j ++ ){ 12 if( i >> j & 1 ){ 13 tmp += a[j]; 14 } 15 } 16 17 //满足子集和为n时,输出答案 18 if( tmp == n ){ 19 for( int j = 0 ; j < 6 ; j ++ ) 20 printf("%2d",i>>j&1); 21 putchar('\n'); 22 } 23 } 24 return 0; 25 return 0; 26 }
背包问题
暴力求解方法:
【题解】 类比子集合问题,枚举所有子集情况,{1,0} "1" 代表物品往背包里放 "0" 代表不操作 每一个子集都是一种方案。 先判断是否满足背包容量的前提下,进而更新答案
1 #include<stdio.h> 2 3 int value[] = { 45 , 25 , 25 }; 4 int weight[] = { 16 , 15 , 15 }; 5 int C = 30 ; 6 int n = 3 ; 7 int maxValue = 0 ; 8 //value , weight 分别代表:每个物品的价值,容量。 9 //C :背包的总容量 10 //n :物品个数 11 //maxVaulue :背包所能获取的最大价值 12 int main() 13 { 14 for (int i = 0 ; i < 1 << n ; i++ ){ 15 int tmpValue = 0 , tmpWeight = 0 ; 16 for( int j = 0 ; j < n ; j ++ ){ 17 if( i >> j & 1 ){ 18 tmpValue += value[j] ; 19 tmpWeight += weight[j] ; 20 } 21 } 22 if( tmpWeight <= C ){ 23 maxValue = tmpValue > maxValue ? tmpValue : maxValue ; 24 } 25 } 26 printf("maxValue = %d\n",maxValue); 27 return 0 ; 28 }
n皇后问题
暴力求解方法:
【题意】 n个皇后放在n*n的棋盘上,皇后之间不能相互攻击(即不能在同一行,同一列,同一对角线上) 请问有多少种方法?
【题解】 如果类比子集和问题,那么n*n的格子进行01方法,但是如果针对8皇后来数,8*8=64 2^64 = 18446744073709551616 计算量很大,无法实现。显而易见,我们通过64个格子进行{0,1}划分显然不可行。 通过对题目的分析发现有冗余的情况,每一列(行)只能放一个皇后。那么在同一行中其余7个位置都是不能放皇后的。那么我们就根据每一列(行)进行放置,每一列(行)中只有8行(列)可以随意放。 问题规模就变成 8(依次枚举8列)^8(每一列共有8种选择) 8^8 = 2 ^ 24 = 16777216 < 1e7 可以接受 暴力枚举相当于枚举八进制下,八个位置的情况。并统计合法方案的个数
1 #include<stdio.h> 2 #include<stdlib.h> 3 const int N = 8 ; 4 int queen[N] ; 5 //判断皇后之间放法是否合法 6 bool check(){ 7 for( int i = 0 ; i < N ; i++ ){ 8 for( int j = 0 ; j < i ; j++ ){ 9 if( queen[i] == queen[j] || abs(i-j) == abs(queen[i]-queen[j]) ) 10 return false ; 11 } 12 } 13 return true ; 14 } 15 int main() 16 { 17 //枚举所有情况,枚举8个位置上的 0~7 18 //统计合法的个数,已知八皇后的方案数为92 19 20 int Count = 0 ; 21 //枚举所有情况 22 for( int i = 0 ; i < 1 << 24 ; i ++ ){ 23 int tmp = i ; 24 //八进制下枚举每一个位置 25 for( int j = 0 ; j < 8 ; j++ ){ 26 //第j列的皇后放置在tmp%8的位置上 27 queen[j] = tmp % 8 ; 28 tmp /= 8 ; 29 } 30 //判断是否合法 31 if( check() ) 32 Count ++ ; 33 } 34 printf("%d\n",Count); 35 return 0; 36 } 37 // 8 ^ 8 = 2 ^(3*8) = 2 ^ 24 = O(16777216) < O(1e7) 一秒内能执行
低碳生活大奖赛
【题意】 某电视台举办了低碳生活大奖赛。题目的计分规则相当奇怪: (1)每位选手需要回答10个问题(其编号为1到10),越后面越有难度。答对的,当前分数翻倍;答错了则扣掉与题号相同的分数(选手必须回答问题,不回答按错误处理)。 (2)每位选手都有一个起步的分数为10分。 某获胜选手最终得分刚好是100分,如果不让你看比赛过程,你能推断出他(她)哪个题目答对了,哪个题目答错了吗? (3)如果把答对的记为1,答错的记为0,则10个题目的回答情况可以用仅含有1和0的串来表示。例如:0010110011 就是可能的情况。 (4) 你的任务是算出所有可能情况。每个答案占一行。
【题解】 枚举所有情况即可,2^10 = 1024 (时间上可以接受) 按照题意依次进行操作, "0" : Score - 10 "1" : Score * 2
1 #include<stdio.h> 2 3 int main() 4 { 5 int n = 10 ; 6 int Count = 0 ; 7 8 //枚举所有情况 9 for( int i = 0 ; i < 1 << 10 ; i++ ){ 10 int Score = 10 ; 11 //根据每个位置上0,1进行操作 12 for(int j = 0 ; j < 10 ; j++ ){ 13 if( i >> j & 1 ){ 14 Score *= 2 ; 15 }else{ 16 Score -= 10; 17 } 18 } 19 //最后得分为100 20 if( Score == 100 ){ 21 //统计方案数 22 Count ++ ; 23 //输出满足题意的一组解 24 for( int j = 0 ; j < 10 ; j++ ){ 25 printf("%-2d",i>>j&1); 26 } 27 putchar('\n'); 28 } 29 } 30 printf("Count = %d\n",Count); 31 return 0; 32 33 }
课后习题
李白饮酒
【题意】:
话说大诗人李白,一生好饮。一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数。
为了使问题更加有趣,我们假设他遇到店s次,花f次,你的任务是计算此时的方案总数。
【题解】
暴力出所有01情况,通过判断过程合法 以及 酒刚好被喝完统计其合法的方案数。
1 #include<iostream> 2 using namespace std; 3 int Shop , Flower , ans , n ; 4 5 int bit( int x ){ 6 int res = 0 ; 7 for( int j = 0 ; j < n ; j++ ){ 8 res += ( x >> j & 1 ); 9 } 10 return res ; 11 } 12 int main() 13 { 14 cin >> Shop >> Flower ; 15 n = Shop + Flower ; 16 17 //枚举所有情况 18 for( int i = 0 ; i < 1<<n ; i++ ){ 19 int tmp = 2 ; 20 bool f = true ; 21 22 if( bit(i) == Shop ){ 23 for( int j = 0 ; j < n ; j++ ){ 24 if( i >> j & 1 ){ 25 tmp = tmp * 2 ; 26 }else{ 27 tmp -- ; 28 29 //过程中不合法:路途中酒壶里没有酒 30 //这样会导致酒壶里没有酒,遇到店乘以2 即( 0 * 2 = 0 ) 31 //而题目要求的是:最后遇到花且刚好把酒给喝完. 32 if( tmp==0 && j!=n-1 ){ 33 f = false ; 34 break ; 35 } 36 } 37 } 38 } 39 //如果过程中没有不合法,同时刚好把酒喝完 40 if( f && tmp == 0 ){ 41 ans ++ ; 42 } 43 } 44 cout << ans << endl ; 45 return 0 ; 46 }
警匪110
【题意】 匪警请拨110,即使手机欠费也可拨通! 为了保障社会秩序,保护人民群众生命财产安全,警察叔叔需要与罪犯斗智斗勇,因而需要经常性地进行体力训练和智力训练! 某批警察叔叔正在进行智力训练: 1 2 3 4 5 6 7 8 9 = 110; 请看上边的算式,为了使等式成立,需要在数字间填入加号或者减号(可以不填,但不能填入其它符号)。之间没有填入符号的数字组合成一个数,例如:12+34+56+7-8+9 就是一种合格的填法;123+4+5+67-89 是另一个可能的答案。 请你利用计算机的优势,帮助警察叔叔快速找到所有答案。 每个答案占一行。形如: 12+34+56+7-8+9 123+4+5+67-89
【题解】 这个题目好比三进制下的暴力枚举过程。 思路非常简单,但是代码需要一定的实现能力才能解决,过程中需要用到 暴搜枚举符号 利用dfs枚举三种情况,到叶子结点进行判断求值 构造字符串 0,1,2 -> "" , "+" , "-"三种情况 因为过程中有""的出现所以构造字符串显得尤为重要 中缀表达式求值 开两个栈进行存储,一个栈存数字,另一栈存符号。 遇到运算符 取出 栈顶两个数进行运算。 把求得结果重新压栈。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 30 ; 5 char str[N] = {"1 2 3 4 5 6 7 8 9"}; 6 char s[N] ; 7 int a[N] ; 8 9 //方案数 , 目标数 10 int ans = 0 ,target;; 11 12 //数字栈,符号栈 13 stack < int > Nums ; 14 stack < char > ops ; 15 16 17 //遇到符号时计算一遍 18 void Calc(){ 19 int tmp = 1 ; 20 int v = Nums.top() ; Nums.pop(); 21 int u = Nums.top() ; Nums.pop(); 22 char ch = ops.top() ; ops.pop() ; 23 if( ch == '+' ) tmp = u + v; 24 else if( ch == '-' ) tmp = u - v ; 25 Nums.push( tmp ) ; 26 } 27 28 29 int Expression(){ 30 31 //初始化操作 32 while( !Nums.empty() ) Nums.pop(); 33 while( !ops.empty() ) ops.pop(); 34 35 int res = 0 , len = 0 ; 36 int Num1 = 0 , Num2 = 0 ; 37 38 //初始化字符串 39 memset( s , '\0' , sizeof s ); 40 41 //构造s = '(12+34+56+7-8+9)'形式 42 s[len++] = '('; 43 for( int i = 0 ; i <=16 ; i++ ){ 44 if( i & 1 ){ 45 if( a[i] == 0 ) continue ; 46 else if( a[i] == 1 ){ 47 s[len++] = '+'; 48 }else if( a[i] == 2 ){ 49 s[len++] = '-'; 50 } 51 }else{ 52 s[len++] = str[i] ; 53 } 54 } 55 s[len++] = ')'; 56 57 //利用栈实现中缀表达式的求值运算 58 for(int i=0 ; i < len ; i++ ){ 59 if( '0' <= s[i] && s[i] <= '9' ){ 60 int tmp = 0 ; 61 int j = i ; 62 while( '0' <= s[j] && s[j] <= '9' ){ 63 tmp = tmp * 10 + s[j] - '0' ; 64 j ++ ; 65 } 66 Nums.push(tmp); 67 i = j - 1 ; 68 }else{ 69 char c = s[i] ; 70 if( c == '(' ){ 71 ops.push(c); 72 }else if( c == '+' || c == '-' ){ 73 while( ops.top() != '(' ) Calc(); 74 ops.push( c ); 75 }else if( c == ')' ){ 76 while ( ops.top() != '(' ) Calc(); 77 ops.pop(); 78 } 79 //else puts(" Invaild Operator !" ); 80 } 81 } 82 83 //printf("%s %d\n",s,len); 84 85 return Num1 = Nums.top() ; 86 } 87 88 //dfs进行爆搜 89 void dfs( int pos ){ 90 if( pos == 8 ){ 91 if( Expression() == target ) 92 ans ++ ; 93 return ; 94 } 95 //三叉树进行遍历 96 for( int i = 0 ; i < 3 ; i++ ){ 97 a[pos*2+1] = i ; 98 dfs( pos + 1 ); 99 } 100 } 101 int main() 102 { 103 cin >> target ; 104 dfs( 0 ); 105 cout << ans << endl ; 106 return 0 ; 107 }
派遣敢死队
【题意】 G将军有一支训练有素的军队,这个军队除开G将军外,每名士兵都有一个直接上级(可能是其他士兵,也可能是G将军)。
现在G将军将接受一个特别的任务,需要派遣一部分士兵(至少一个)组成一个敢死队,
为了增加敢死队队员的独立性,要求如果一名士兵在敢死队中,他的直接上级不能在敢死队中。
请问,G将军有多少种派出敢死队的方法。注意,G将军也可以作为一个士兵进入敢死队。 输入的第一行包含一个整数n,表示包括G将军在内的军队的人数。军队的士兵从1至n编号,G将军编号为1。
接下来n-1个数,分别表示编号为2, 3, ..., n的士兵的直接上级编号,编号i的士兵的直接上级的编号小于i。
【题解】 暴力枚举 n位二进制,枚举每个人是否被选上敢死队 过程中判断是否合法(自己直属上司 不能和自己同时在队伍中)。 注意细节: 1. G将军没有上司 2. 敢死队至少有一个人
1 #include<iosteram> 2 using namespace std; 3 const int N = 22; 4 int a[N]; 5 //a[i] : 第i个人的上司为 a[i] 6 7 int main() 8 { 9 int n , ans = 0 ; 10 cin >> n ; 11 12 //G将军特殊处理,他没有上司,所以他的上司设置为一个不存在的值方便统一处理 13 a[0] = n+1 ; 14 15 bool f ; 16 //编号 1~n -> 0 ~ n-1 17 for( int i = 1 ; i < n ; i++ ) 18 cin >> a[i] , a[i] -- ; 19 20 //暴力枚举所有情况,注意从1开始 21 for( int i = 1 ; i < 1 << n ; i++ ){ 22 f = true ; 23 24 for( int j = 0 ; j < n ; j++ ){ 25 //两种合法情况:当前没有选上敢死队 或者 他的直属上司不在队伍中 26 if( !(i >> j & 1) || 27 ( (i >> j & 1) && !( i >> a[j] & 1 ) ) ){ 28 continue ; 29 }else{ 30 f = false ; 31 break ; 32 } 33 } 34 if( f ) ans ++ ; 35 } 36 printf("%d\n",ans); 37 return 0; 38 }
处理机调度问题
【题意】
用两台处理机A和B处理n个作业。设第i个作业交给A处理需要时间ai,交给B处理需要时间bi。
由于各作业的特点和机器的性能关系,ai和bi之间没有明确的大小关系。
既不能将一个作业分开由2台机器处理,也没有一台机器能同时处理2个作业。
设计一个算法,使得这两台机器处理完这n个作业的时间最短。
【题解】 暴力枚举n位二进制的所有情况. 当枚举第i位时: "1" -> A机器工作 A += a[i] "0" -> B机器工作 B += b[i] 两台机器的最长时间是这种情况的工作时间
1 #include<iostream> 2 using namespace std; 3 const int N = 30 ; 4 int a[N] , b[N] ; 5 int main() 6 { 7 int n ; 8 cin >> n ; 9 for( int i = 0 ; i < n ; i++ ){ 10 cin >> a[i] ; 11 } 12 for( int i = 0 ; i < n ; i++ ){ 13 cin >> b[i] ; 14 } 15 int A , B , Ans = 0x3f3f3f3f ; 16 for( int i = 0 ; i < 1 << n ; i++ ){ 17 A = B = 0 ; 18 19 for( int j=0 ; j < n ; j++ ){ 20 if( i >> j & 1 ){ 21 A += a[j] ; 22 }else{ 23 B += b[j] ; 24 } 25 } 26 //A,B两台机器同时工作,取决定性的时间最长的那台 27 //答案是记录每一种情况中耗时最少的 28 Ans = min( Ans , max(A,B) ); 29 } 30 cout << Ans << endl; 31 return 0 ; 32 }
组素数
【题意】 素数就是不能再进行等分的数。比如:2、3、5、7、11 等。9 = 3 * 3 说明它可以3等分,因而不是素数。 我们国家在1949年建国。如果只给你 1、9、4和9 这4个数字卡片,可以随意摆放它们的先后顺序,那么,你能组成多少个4位的素数呢? 比如:1949,4919 都符合要求。 为了使问题更加有趣,我们输入n个数字,求这n个数字可以组成的数字中的素数。
【题解】 我个人认为这个题不应该放在暴力专题中,因为这个题目涉及的是两个经典问题的组合 1、判断一个数是否为素数? a.其中可以用线性筛或者用埃氏筛预处理O(1e7), 放置在一个数组中,is_prime[]进行判断即可 b.暴力枚举 根号n 内的因子 O(根号n) 2、不全相异全排列问题 经典的搜索问题 而我的做法是正儿八经的暴力。。。 第一步:预处理1e7内哪些是素数,哪些不是 第二步:用全排列函数实现所有组合情况 6! 第三步:排序 第四步:去重复元素 第五步:输出答案
1 #include<iostream> 2 using namespace std; 3 typedef long long ll; 4 const int M = 1e3+10 ; 5 const int N = 1e7; 6 int a[M],ans[M],n; 7 8 bool is_prime[N] ;//判断 i 是否为素数. 如果是素数则is_prime[i] = 0 9 int prime[N] ; 10 int tot ; 11 12 //素数筛 13 void Euler(){ 14 is_prime[0] = is_prime[1] = 1 ; 15 for( ll i = 2 ; i < N ; i ++ ){ 16 if( is_prime[i] == 0 ){ 17 prime[tot++] = i ; 18 } 19 for( ll j = 0 ; j < tot && (long long) i < N / prime[j] ; j++ ){ 20 is_prime[ i *prime[j] ] = 1 ; 21 if( i % prime[j] == 0 ) break ; 22 } 23 } 24 } 25 26 int main() 27 { 28 Euler() ; 29 cin >> n ; 30 for( int i = 0 ; i < n ; i++ ) 31 cin >> a[i] ; 32 sort( a , a+n ); 33 int cnt = 0 ; 34 35 //next_permutation ( a , a + n ) 36 //全排列函数 37 do{ 38 int tmp = 0 ; 39 for( int i = 0 ; i < n ; i++ ){ 40 tmp = tmp * 10 + a[i]; 41 } 42 if( !is_prime[tmp] ){ 43 ans[cnt++] = tmp ; 44 } 45 46 }while( next_permutation(a,a+n) ); 47 48 //sort( ans , ans + cnt ) 快排函数 49 //cnt = unique( ans , ans + cnt ) - ans 去重函数,返回新的个数 50 sort( ans , ans + cnt ); 51 cnt = unique( ans , ans + cnt ) - ans ; 52 53 if( cnt == 0 ){ 54 cout << -1 << endl; 55 }else{ 56 for( int i = 0 ; i < cnt ; i++ ){ 57 cout << ans[i] << endl; 58 } 59 } 60 return 0 ; 61 } 62 /* 63 64 6 65 3 3 5 7 8 9 66 67 */