Regionals 2009 Asia - Hsinchu UVALIVE, 4525 - Clues 搜索

来源:互联网 发布:单片机的32个引脚介绍 编辑:程序博客网 时间:2024/06/04 22:26

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=350&page=show_problem&problem=2526

题目大意:

话说岛国有位博士,想要保护一个数据的安全,这个数是个质数,假设是k0。他的策略是这样的,首先他选择一个r,r>=1,和一个空集合C,然后选择r-1个不超过k0的质数,k1,k2,。。。,k(r-1),然后把r加到集合C中。第二步,对于每一个k0到k(r-1)。他要么直接把k放进集合,要么把k拆成几个数(随便拆,只要和等于k就行)然后把拆出来的数放进集合。最后一步,将集合里面所有的数按照非递减的顺序排列。

由于教授年纪有些大了,脑子不太好使,让你帮他个忙,通过最后的集合找出原来的k,对于饱经ACM训练的你来说,这还不是小菜一碟,一听老教授的要求,灵光一动,便老练的说到,“你这个有多种情况啊”,只见年迈的老教授眼中精光一闪,心想,“小伙子有几把刷子啊”,“这样吧,那你就找出你能恢复出来的最大质数好了”。


于是,善良的你,便不知不觉落进了猎人的圈套。。


思路:

首先,根据题目要求,集合中肯定有一个r,也就是最终质数的个数。那么首先枚举r,然后对于剩下的元素,由于元素个数最多只有14个,那么可以用二进制枚举的形式,找出能够组成的所有质数,判断这些质数对应二进制集合相互没有交集能否组成r个,并找出能组成的最大值就是最后答案。


对于每一个r,和所有剩下元素组成的质数集合,可以用dp来进行后续的判断。

dp[i][s]表示s所有二进制位为1那一位对应的数的集合组成i个质数后其中最大的质数。

那么,对于质数集合中的一个质数v,以及对应的二进制集合t,如果t与s没有交集,即s&t==0,那么,

dp[i+1][s|t] = max(dp[i+1][s|t],max(dp[i][s],v));

最后dp[r][(1<<n-1)-1] 就是当前r对应的质数最大值。


代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;#define maxn 200000#define inf 0x3fffffffint n;int a[20],b[20];bool fac[maxn];int ans;struct Node{int val;int s;Node(){}Node(int a,int b):val(a),s(b){}};vector<Node> vec;int dp[20][maxn];void init(){memset(fac,false,sizeof(fac));fac[0] = fac[1] = true;for(int i=2;i<maxn;i++){if(!fac[i]){for(int j=i*2;j<maxn;j+=i){fac[j] = true;}}}//for(int i=2;i<100;i++){//if(!fac[i]) printf("%d\n",i);//}}void check(int r){for(int i=0;i<=r;i++){for(int s=0;s<1<<(n-1);s++) dp[i][s] = 0;}for(int i=0;i<vec.size();i++) dp[1][vec[i].s] = vec[i].val;for(int i=1;i<r;i++){for(int s=0;s<1<<(n-1);s++){if(dp[i][s]==0) continue;   //当前状态无法拼出质数 for(int k=0;k<vec.size();k++){if(s&vec[k].s) continue;   //vec[i].s 存在元素已经被选择int t = vec[k].s;dp[i+1][s|t] = max(dp[i+1][s|t],max(vec[k].val,dp[i][s]));}}}ans = max(ans,dp[r][(1<<(n-1))-1]);}void solve(){ans = 0;for(int i=0;i<n && a[i]<n;i++){  // 枚举r if(i>0 && a[i]==a[i-1]) continue;  // 避免重复 memcpy(b,a,sizeof(a));b[i] = inf;  // b[i] is rswap(b[i],b[n-1]);vec.clear(); for(int s=0;s<1<<(n-1);s++){int sum = 0;for(int k=0;k<n-1;k++){if(s&(1<<k)) sum += b[k];   //枚举所有能够拼出的质数   存放到vec中 }if(!fac[sum]) {vec.push_back(Node(sum,s));//printf("r:%d sum:%d\n",a[i],sum);}}check(a[i]);//printf("xxxxxxxxxxxxxxx\n");}if(ans==0) printf("not a valid clue\n");else printf("%d\n",ans);}int main(){init();int cnt=1;while(scanf("%d",&n)){if(n==-1) break;for(int i=0;i<n;i++) scanf("%d",&a[i]);printf("Case %d: ",cnt++);solve();}return 0;}



0 0
原创粉丝点击