小明的密码-初级DP解法

#include
#include
#include
using namespace std;
int visited[5][20][9009];// 访问情况
int dp[5][20][9009];  // M N num num即M-1位的数字
int num_2[7]= {2,3,5,7,11,13,17};
int num_3[9]= {2,3,5,7,11,13,17,19,23};
int num_4[11]= {2,3,5,7,11,13,17,19,23,29,31};  //存储素数
int N,M;
int delete_head(int num,int m)  //去掉当前数字的首个数字
{
    int ans;
    if (m==2) return 0;
    if (m==3) ans=num-num/10*10;
    if (m==4) ans=num-num/100*100;
    return ans;
}
int divide_num(int num)
{
    int ans=0;
    while (num>0)
    {
        ans+=num;
        num=num/10;
    }
    return ans;
}
int select_num(int k,int sum,int m)
{
    if (m==2)
    {
        for (int i=0; i<7; i++) if (k+divide_num(sum)==num_2[i]) return 1;
        return 0;
    }
    if (m==3)
    {
        for (int i=0; i<9; i++)
            if (k+divide_num(sum)==num_3[i])
            {
                return 1;
            }
        return 0;
    }
    if (m==4)
    {
        for (int i=0; i<11; i++) if (k+divide_num(sum)==num_4[i]) return 1;
        return 0;
    }
}
void work(int m,int n,int num)
{
    if (n==0)  // n=0直接处理
    {
        visited[m][n][num]=1;
        dp[m][n][num]=1;
    }
    else
    {
        if (!visited[m][n][num])
        {
            visited[m][n][num]=1;
            for (int k=0; k<=9; k++)
            {
                if (select_num(k,num,m))
                {
                    int next=delete_head(num,m)*10+k; //next是num的下个状态(去头加尾)
                    if (!visited[m][n-1][next])
                    {
                        work(m,n-1,next);
                    }
                    dp[m][n][num]+=dp[m][n-1][next];
                }
            }
        }
    }
}
int main()
{
    memset(visited,0,sizeof(visited));
    memset(dp,0,sizeof(dp));
    scanf("%d %d",&N,&M);
    if (M==1)
    {
        int ans=1;
        while (N>0)
        {
            ans*=4;
            N--;
        }
        printf("%d
",ans);
    }
    if (M==2)
    {
        int ans=0;
        for (int i=0; i<=9; i++)
        {
            int num=i;
            work(M,N-1,num);
            ans+=dp[M][N-1][num];
        }
        printf("%d
",ans);
    }
    if (M==3)
    {
        int ans=0;
        for (int i=0; i<=9; i++)
            for (int k=0; k<=9; k++)
            {
                int num=i*10+k;
                work(M,N-2,num);
                ans+=dp[M][N-2][num];
            }
        printf("%d
",ans);
    }
    if (M==4)
    {
        int ans=0;
        for (int i=0; i<=9; i++)
            for (int k=0; k<=9; k++)
                for (int x=0; x<=9; x++)
                {
                    int num=i*100+k*10+x;
                    work(M,N-3,num);
                    ans+=dp[M][N-3][num];
                }
        printf("%d
",ans);
    }
    return 0;
}

  

小明的密码由N(1<=N<=12)个数字构成,每个数字都可以是0至9中任意一个数字,但小明的密码还有 一个特点就是密码中连续的M(1<=M<=4)个数字的和是质数,现给定M和N,求满足条件的密码共有多少 个? 输入格式 第1行是T,case数量,此后T行,每行两个数,N和M 输出格式 每个case输出一个满足条件的密码总数 
输入样例 
1 1 
2 1 
输出样例 
16 
作者 admin
第一次做多维DP,虽然才做到第三个维度,感觉已经够狠的题目还可以出的更复杂,比如M更大的时候我还没想过怎么操作,暂时做到三维DP,主要是做第三维的时候遇到困难,第一次做的时候把前M-1位的数字和求出来做参数,没想到维度混淆了,还是只能用M-1做真整数,这样如果M稍微大一点,我可能都要做高精度了,而且内存也不宽裕,继续努力想其他解法吧
  1 #include <cstdlib>
  2 #include <cstdio>
  3 #include  <cstring>
  4 using namespace std;
  5 int visited[5][20][9009];// 访问情况
  6 int dp[5][20][9009];  // M N num num即M-1位的数字
  7 int num_2[7]= {2,3,5,7,11,13,17};
  8 int num_3[9]= {2,3,5,7,11,13,17,19,23};
  9 int num_4[11]= {2,3,5,7,11,13,17,19,23,29,31};  //存储素数
 10 int N,M;
 11 int delete_head(int num,int m)  //去掉当前数字的首个数字
 12 {
 13     int ans;
 14     if (m==2) return 0;
 15     if (m==3) ans=num-num/10*10;
 16     if (m==4) ans=num-num/100*100;
 17     return ans;
 18 }
 19 int divide_num(int num)
 20 {
 21     int ans=0;
 22     while (num>0)
 23     {
 24         ans+=num;
 25         num=num/10;
 26     }
 27     return ans;
 28 }
 29 int select_num(int k,int sum,int m)
 30 {
 31     if (m==2)
 32     {
 33         for (int i=0; i<7; i++) if (k+divide_num(sum)==num_2[i]) return 1;
 34         return 0;
 35     }
 36     if (m==3)
 37     {
 38         for (int i=0; i<9; i++)
 39             if (k+divide_num(sum)==num_3[i])
 40             {
 41                 return 1;
 42             }
 43         return 0;
 44     }
 45     if (m==4)
 46     {
 47         for (int i=0; i<11; i++) if (k+divide_num(sum)==num_4[i]) return 1;
 48         return 0;
 49     }
 50 }
 51 void work(int m,int n,int num)
 52 {
 53     if (n==0)  // n=0直接处理
 54     {
 55         visited[m][n][num]=1;
 56         dp[m][n][num]=1;
 57     }
 58     else
 59     {
 60         if (!visited[m][n][num])
 61         {
 62             visited[m][n][num]=1;
 63             for (int k=0; k<=9; k++)
 64             {
 65                 if (select_num(k,num,m))
 66                 {
 67                     int next=delete_head(num,m)*10+k; //next是num的下个状态(去头加尾)
 68                     if (!visited[m][n-1][next])
 69                     {
 70                         work(m,n-1,next);
 71                     }
 72                     dp[m][n][num]+=dp[m][n-1][next];
 73                 }
 74             }
 75         }
 76     }
 77 }
 78 int main()
 79 {
 80     memset(visited,0,sizeof(visited));
 81     memset(dp,0,sizeof(dp));
 82     scanf("%d %d",&N,&M);
 83     if (M==1)
 84     {
 85         int ans=1;
 86         while (N>0)
 87         {
 88             ans*=4;
 89             N--;
 90         }
 91         printf("%d
",ans);
 92     }
 93     if (M==2)
 94     {
 95         int ans=0;
 96         for (int i=0; i<=9; i++)
 97         {
 98             int num=i;
 99             work(M,N-1,num);
100             ans+=dp[M][N-1][num];
101         }
102         printf("%d
",ans);
103     }
104     if (M==3)
105     {
106         int ans=0;
107         for (int i=0; i<=9; i++)
108             for (int k=0; k<=9; k++)
109             {
110                 int num=i*10+k;
111                 work(M,N-2,num);
112                 ans+=dp[M][N-2][num];
113             }
114         printf("%d
",ans);
115     }
116     if (M==4)
117     {
118         int ans=0;
119         for (int i=0; i<=9; i++)
120             for (int k=0; k<=9; k++)
121                 for (int x=0; x<=9; x++)
122                 {
123                     int num=i*100+k*10+x;
124                     work(M,N-3,num);
125                     ans+=dp[M][N-3][num];
126                 }
127         printf("%d
",ans);
128     }
129     return 0;
130 }
View Code

原文地址:https://www.cnblogs.com/Lionel002/p/5441000.html