[NOIP2002 普及组] 选数
题目链接 https://www.luogu.com.cn/problem/P1036
又是一道小小的(呸!)搜索
提交了好几次都WA了TuT
此题需要去重,这也是本题的重难点
如何去重?
那就要说一下刚见识到的“不降原则”了
那什么是不降原则嘞?
举个例子: 比如说在6里面随便选5个数,那么选法都是什么呢? 瞎枚举? 12345 12346 前两个还不会弄混 然后很可能就乱了 少点数可能不会乱 但是多了就不好整了 比如说在100里随便选50个数。 1 2 3 4 5 6 7 8 9 10 11 12...... Die. 所以我们可以运用不降原则: 保证枚举的这些数是升序排列 其实真正的不降原则还可以平 比如 1 2 2 3 3 4...... 但是请注意这道题也不能平 否则就有重复数字了 拿6个里面选3个举例子 1 2 3 1 2 4 1 2 5 1 2 6 第一轮枚举完毕。 第二个数加一 1 3 ? 这个“?”应该是4,因为是升序排列 1 3 4 1 3 5 1 3 6 接着,就是这样 1 4 5 1 4 6 1 5 6 第一位是1枚举完毕 第一位是2呢? 2 3 4 2 3 5 2 3 6 2 4 5 2 4 6 2 5 6 就是这样的,枚举还是蛮清晰的吧 以此类推..... 3 4 5 3 4 6 3 5 6 4 5 6 然后就枚举不了了,结束。 所以说,这样就可以避免判重了。
一开始用了next_permutation怎么也想不明白为什么不给我AC,原来是没去重
(我真傻,真的……)
放一下AC代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,k; 4 long long int ans=0; 5 int a[25],b[25]; 6 bool isprime(int x)//判断质数不多说 7 { 8 for(int i=2;i<=sqrt(x);i++) 9 if(x%i==0) return false; 10 return true; 11 } 12 void dfs(int m,int sum,int rise) 13 //m表示已经选了m个数,sum为当前的和,rise表示升序排列 14 { 15 if(m==k)//如果已经选了k个数 16 { 17 if(isprime(sum))//并且和为素数 18 ans++; 19 return ;//则返回 20 } 21 for(int i=rise;i<=n;i++) 22 dfs(m+1,sum+a[i],i+1);//步数+1,升序排列i+1,避免算重 23 return ; 24 } 25 int main() 26 { 27 cin>>n>>k; 28 for(int i=1;i<=n;i++) 29 cin>>a[i]; 30 dfs(0,0,1); 31 cout<<ans; 32 return 0; 33 }
yeah!