POJ 3842

题意:给你一串数字,问你他们能组成多少个不同的素数。思路:枚举这些数字的组合的排列,打一张素数表直接判断。这题时间限制很紧啊(1000ms),在无限TLE之后,我把memset(vis,0,sizeof(vis))这句删除之后跑了844ms,险过,memset怎么会那么坑,不是说内部实现是调用批处理吗,为什么还那么慢???另外,打素数表的时候,注意姿势。。。,不然必然超时。
Ps:按照刚进实验室时某大三学长教我的那个写法打素数表时超时,当时他还说两种方法都一样,现在才发现坑了我们。下面是三个版本的:1.dfs+二进制枚举优化 (844ms)

1.dfs+二进制枚举优化 (844ms):
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define MAXN 10000000
char isp[MAXN], visp[MAXN], vis[MAXN];
int a[10], t[10], sum;
void init(){
    memset(isp, 0, sizeof(isp));
    isp[0] = isp[1] = 1;
    for(int i = 2;i*i<MAXN;i ++)
        if(!isp[i])
            for(int j = i*i;j < MAXN;j += i)
                isp[j] = 1;
    return;
}
int ToNum(int n){
    int sum = 0;
    for(int i = 0;i < n;i ++) sum = sum*10 + t[i];
    return sum;
}
void dfs(int n, int dep){
    if(dep == n){
        int tmp = ToNum(n);
        if(!isp[tmp] && !visp[tmp]){
            sum++;
            visp[tmp] = 1;
        }
        return;
    }
    for(int i = 0;i < n;i ++){
        if(!vis[i]){
            vis[i] = 1;
            t[dep] = a[i];
            dfs(n, dep+1);
            vis[i] = 0;
        }
    }
}
int main(){
    char str[10];
    int tt, n, b[10];
    init();
    scanf("%d", &tt);
    while(tt--){
        memset(str, 0, sizeof(str));
        scanf("%s", str);
        int len = strlen(str);
        for(int i = 0;i < len;i ++) b[i] = str[i]-'0';
        memset(visp, 0, sizeof(visp));
        int ans = 0;
        int UP = (1 << len);
        for(int i = 1;i < UP;i ++){
            int k = 0;
            for(int j = 0;j < len;j ++)
                if(i & (1 << j)) a[k++] = b[j];
            sum = 0;
            //memset(vis,0,sizeof(vis); 这句加上就超时。。。
            dfs(k, 0);
            ans += sum;
        }
        printf("%d\n", ans);
    }
    return 0;
}

2. 普通dfs不加优化(969ms。。。):
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define MAXN 10000000
char isp[MAXN], visp[MAXN], vis[MAXN];
int a[10], t[10], sum;
void init(){
    memset(isp, 0, sizeof(isp));
    isp[0] = isp[1] = 1;
    for(int i = 2;i*i<MAXN;i ++)
        if(!isp[i])
            for(int j = i*i;j < MAXN;j += i)
                isp[j] = 1;
    return;
}
int ToNum(int n){
    int sum = 0;
    for(int i = 0;i < n;i ++) sum = sum*10 + t[i];
    return sum;
}
void dfs(int n, int dep, int cnt){
    if(dep == cnt){
        int tmp = ToNum(cnt);
        if(!isp[tmp] && !visp[tmp]){
            sum++;
            visp[tmp] = 1;
        }
    }
    for(int i = 0;i < n;i ++){
        if(!vis[i]){
            vis[i] = 1;
            t[dep] = a[i];
            dfs(n, dep+1, cnt);
            vis[i] = 0;
        }
    }
}
int main(){
    char str[10];
    int tt, n;
    init();
    scanf("%d", &tt);
    while(tt--){
        memset(str, 0, sizeof(str));
        scanf("%s", str);
        int len = strlen(str);
        for(int i = 0;i < len;i ++) a[i] = str[i]-'0';
        memset(visp, 0, sizeof(visp));
        int ans = 0;
        for(int i = 1;i <= len;i ++){
            //memset(vis, 0, sizeof(vis)); 加上就超时。。。
            sum = 0;
            dfs(len, 0, i);
            ans += sum;
        }
        printf("%d\n", ans);
    }
    return 0;
}
3.C++ STL库 next_permutation(a,a+k)函数 + 二进制优化(813ms),可以看出并不比dfs快多少,况且没有调用ToNum函数,减少了程序运行时跳转的时间:
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define MAXN 10000000
using namespace std;
char isp[MAXN], visp[MAXN], vis[MAXN];
int a[10], t[10], sum;
void init(){
    memset(isp, 0, sizeof(isp));
    isp[0] = isp[1] = 1;
    for(int i = 2;i*i<MAXN;i ++)
        if(!isp[i])
            for(int j = i*i;j < MAXN;j += i)
                isp[j] = 1;
    return;
}
int ToNum(int n){
    int sum = 0;
    for(int i = 0;i < n;i ++) sum = sum*10 + a[i];
    return sum;
}
void dfs(int n, int dep){
    if(dep == n){
        int tmp = ToNum(n);
        if(!isp[tmp] && !visp[tmp]){
            sum++;
            visp[tmp] = 1;
        }
        return;
    }
    for(int i = 0;i < n;i ++){
        if(!vis[i]){
            vis[i] = 1;
            t[dep] = a[i];
            dfs(n, dep+1);
            vis[i] = 0;
        }
    }
}
int main(){
    char str[10];
    int tt;
    init();
    scanf("%d", &tt);
    while(tt--){
        memset(str, 0, sizeof(str));
        scanf("%s", str);
        int len = strlen(str);
        sort(str, str+len);
        memset(visp, 0, sizeof(visp));
        int ans = 0, UP = (1 << len);
        for(int i = 1;i < UP;i ++){
            int k = 0;
            for(int j = 0;j < len;j ++)
                if((i >> j) & 1) a[k++] = str[j]-'0';
            sum = 0;
            //memset(vis,0,sizeof(vis)) 加上同样超时。。。
            do{
                int tmp = 0;
                for(int i = 0;i < k;i ++) tmp = tmp*10+a[i];
                if(!isp[tmp] && !visp[tmp]){
                    sum++;
                    visp[tmp] = 1;
                }
            }while(next_permutation(a, a+k));
            ans += sum;
        }
        printf("%d\n", ans);
    }
    return 0;
}


转载于:https://www.cnblogs.com/wangzhili/p/3950232.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值