zoukankan      html  css  js  c++  java
  • 洛谷 P1025 数的划分 & LOJ #10018. 「一本通 1.3 例 1」数的划分

    CSDN同步

    洛谷原题链接

    ( ext{LOJ}) 原题链接

    愉快的三倍经验题。

    简要题意:

    给定 (n,k),求将 (n) 分为 (k) 个有序正整数之和 的方案数。

    (6 leq n leq 200 , 2 leq k leq 6).

    算法一

    搜索 + 剪枝。

    状态设计

    首先我们应当考虑,如何设计搜索状态。

    对本问题即以下的问题:

    • 如何保证和为 (n)?
    • 如何保证共 (k) 个数?
    • 如何保证有序?

    第一问,我们需要一个 sum,记录当前所选数的和。

    第二问,我们需要一个 p,记录当前所选数的个数。

    第三问,我们需要一个 ma,记录当前所选数的最大值(其实也即上次选的数)。

    那么,每次从 ma - sum 进行一个区间枚举即可。

    但是时间复杂度是 指数级 的,不得不说对 (n = 200 , k = 6) 的数据是可以通过的,因为方案数有限;但是数据一旦加强,后果不堪设想。

    剪枝

    以样例为例,(n=7,k=3).

    第一个数你会选 (3) 吗?显然不会,因为后面的数就算都取最小((3)) 也是 (3 imes 3 = 9 > 7) 了。

    所以,我们需要时刻保证 ma * (k-p+1)+sum<=n,即包括当前数在内 (k-p+1) 个数都选最小的 ma,最小的和如果超过 (n),说明无效。如果 (=n),计入答案。即 (geq n) 的情况都可以去除。这样快了很多!

    时间复杂度:(mathcal{O}( ext{wys})).

    实际得分:(100pts).

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
    
    inline void write(int x) {
    	if(x<0) {putchar('-');write(-x);return;}
    	if(x<10) {putchar(char(x%10+'0'));return;}
    	write(x/10);putchar(char(x%10+'0'));
    }
    
    int n,k,s=0;
    
    inline void dfs(int sum,int p,int ma) {
    //	printf("%d %d %d %d
    ",sum,p,ma,s);
    	if(p==k) {s+=(n-sum>=ma);return;}             // 最后一个数的选择剪枝
    	if(sum>=n) return;                            // 最后一个数还没选的情况下,和超过,剪枝       
    	if(ma*(k-p+1)+sum>n) return;
    	if(ma*(k-p+1)+sum==n) {s++;return;}           // 刚才说的两个剪枝
    	for(int i=ma;i<=n-sum;i++) dfs(sum+i,p+1,i);  // 往下一层走
    }
    
    int main() {
    	n=read(),k=read();
    	dfs(0,1,1);
    	write(s);
    	return 0;
    }
    
    
    

    (n=200 , k=6) 的情况这样的剪枝没有什么显著作用,本地测试该剪枝加与不加存在约 (1.5) 倍的差异。当然通过是肯定能通过的。

    于是本人本地测试了 (n = 200 , k = 10) 的数据。得到的结果:加剪枝,约 (55.4s);不加剪枝,约 (146.6s). 可以看到,在大数据的驱使下,剪枝的效率得到了超高的发挥,效率达到了约 (2.65) 倍!(当然,本人电脑极慢,( ext{CPU}) 内存分配给 ( ext{C++}) 的还是太少了)

    算法二

    考虑动态规划。

    易知,我们只要反手开一个记忆化,立刻复杂度变成 (mathcal{O}(nk)).

    代码略,在原搜索基础上修正即可。

  • 相关阅读:
    tp6 控制器不存在:appindexcontrollerIndex
    thinkphp助手函数
    thinkphp5.1、thinkphp6
    lnmp安装
    关于像秒杀这种高并发场景的解决方案
    C# 基于hslcommunication的异步,同步,一对多,webapi等跨程序网络框架实现,适用程序-程序通信
    C# 调用Python脚本 python脚本反调用C#方法 python脚本调用另一个脚本
    C# webapi服务器,创建自定义的,简单的web服务器,供远程接口调用
    C# 创建mqtt服务器,mqtt发布数据,验证逻辑
    C# 实现 websocket 服务器 发送客户端网页前端数据,C#和网页前端通信
  • 原文地址:https://www.cnblogs.com/bifanwen/p/13445604.html
Copyright © 2011-2022 走看看