zoukankan      html  css  js  c++  java
  • SGU 116 Index of super-prime 数论+完全背包+输出方案

    题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=116

    题意好晦涩

    给你一个不超过一万的数 问它最少可以用多少个“超级素数”来表示 使“超级素数”之和等于它 如果无法这样表示 输出0 否则 按非降序形式输出方案

    数论部分就模板的问题 没什么说的

    完全背包方面也很常规

    说说【输出方案】

    背包九讲的伪码给的是二维dp[]的方法

    实际上稍加改动就可以用在一维数组上

    用一个rec[]记录dp[]的当前状态是从哪个状态转移而来(即上一个状态)

    通过两个状态之间的“跨度”来求得“这一跨越是通过选取哪个物品来实现的”

    应该可以证明 这种做法一定可以通过逆推还原出方案

    对于此题的非降序要求

    因为我们的物品(超级素数)是升序排列的

    所以可以证明 逆推出来的东西一定是非降序的

    #include <cstdio>
    #include <cstdlib>
    #include <ctime>
    #include <iostream>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    #include <set>
    #include <queue>
    #include <vector>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 35005;
    const int maxm = 10010;
    const int INF = 100000;
    
    int prim[maxn];
    int s_prim[maxn];
    bool vis[maxn];
    int tot;
    int n;
    
    void work()
    {
        memset(vis, 0, sizeof(vis));
        tot = 0;
        prim[tot++] = 2;
        int t = 10010;
        for(int i = 3; i <= t; i += 2)
        {
            if(vis[i])
                continue;
    
            for(int j = i*i; j <= t; j += 2*i)
                vis[j] = true;
    
            prim[tot++] = i;
        }
    }
    
    int dp[maxm];
    int rec[maxm];
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
    
        work();
    
        int tot2 = 0;
        for(int i = 0; i < tot; i++)
        {
            if(prim[prim[i] - 1] > 10000)
                break;
    
            s_prim[tot2++] = prim[prim[i] - 1];
        }
    
        int m;
        scanf("%d", &m);
    
        fill(dp, dp + 10010, INF);
        dp[0] = 0;
    
        for(int i = 0; i < tot2; i++)
        {
            for(int j = s_prim[i]; j <= m; j++)
            {
                if(dp[j-s_prim[i]] + 1 < dp[j])
                {
                    dp[j] = dp[j-s_prim[i]] + 1;
                    rec[j] = j - s_prim[i];
                }
            }
        }
    
        if(dp[m] == INF)
        {
            printf("0
    ");
            return 0;
        }
    
        int pt = m;
        printf("%d
    ", dp[m]);
        while(pt != 0)
        {
            printf("%d", pt - rec[pt]);
            pt = rec[pt];
            printf("%c", " 
    "[pt == 0]);
        }
    
        return 0;
    }
  • 相关阅读:

    【工作】---前后端联调
    【react】---Immutable的基本使用
    【react】传值
    【原生】 HTML DOM 事件,各种事件类型、事件种类
    两台笔记本电脑之间实现屏幕扩展
    【看图学习后台管理系统】
    【bug】在react开发中,使用link 跳转中,无法点击跳转的问题
    【前端工程师】 web 安全问题
    【前端工程师】 性能和效率 优化的问题
  • 原文地址:https://www.cnblogs.com/dishu/p/4296332.html
Copyright © 2011-2022 走看看