C++ 谁能降低我代码的复杂性呢。Codeforces Round113第2部分的问题E

C++ 谁能降低我代码的复杂性呢。Codeforces Round113第2部分的问题E,c++,recursion,optimization,data-structures,dynamic-programming,C++,Recursion,Optimization,Data Structures,Dynamic Programming,问题的链接: 问题陈述: *给你一个四面体。让我们用字母A、B、C和D相应地标记它的顶点 一只蚂蚁站在四面体的顶点D上。蚂蚁很活跃,不会闲着。在每个时刻,他都会沿着四面体的某个边缘从一个顶点跨到另一个顶点。蚂蚁不能站在一个地方。 你不需要做很多事情来解决这个问题:你的任务是计算蚂蚁从初始顶点D到自身的方式的数量,精确到n步。换句话说,要求您找出从顶点D到自身长度为n的不同循环路径的数量。由于数字可能相当大,您应该以100000007(10^9)为单位打印它 + 7) * 输入: 第一行只包含整数

问题的链接:

问题陈述:

*给你一个四面体。让我们用字母A、B、C和D相应地标记它的顶点

一只蚂蚁站在四面体的顶点D上。蚂蚁很活跃,不会闲着。在每个时刻,他都会沿着四面体的某个边缘从一个顶点跨到另一个顶点。蚂蚁不能站在一个地方。 你不需要做很多事情来解决这个问题:你的任务是计算蚂蚁从初始顶点D到自身的方式的数量,精确到n步。换句话说,要求您找出从顶点D到自身长度为n的不同循环路径的数量。由于数字可能相当大,您应该以100000007(10^9)为单位打印它 + 7) *

输入: 第一行只包含整数n(1) ≤ N ≤ 107)-循环路径的所需长度

输出: 打印唯一的整数-所需的方式数,模为100000007(10e9 + 7)

示例:输入n=2,输出:3 输入n=4,输出:21

我解决问题的方法: 我已经编写了一个递归代码,它接受两个输入n和当前索引,然后我将遍历并探索所有可能的组合

#include<iostream>
using namespace std;
#define mod 10000000
#define ll long long   
ll count_moves=0;
ll count(ll n, int present)
{   
    if(n==0 and present==0) count_moves+=1, count_moves%=mod;  //base_condition
    else if(n>1){   //Generating All possible Combinations 
        count(n-1,(present+1)%4);
        count(n-1,(present+2)%4);
        count(n-1,(present+3)%4);
    }
    else if(n==1 and present) count(n-1,0);
}

int main()
{
    ll n;  cin>>n;
    if(n==1) { 
         cout<<"0";  return;   
    } 
    count(n,0);
    cout<<count_moves%mod;
}
#包括
使用名称空间std;
#定义模10000000
#定义ll long long
ll count_moves=0;
ll计数(ll n,整数当前)
{   
如果(n==0和present==0)count\u moves+=1,count\u moves%=mod;//基本条件
else如果(n>1){//生成所有可能的组合
计数(n-1,(存在+1)%4);
计数(n-1,(存在+2)%4);
计数(n-1,(存在+3)%4);
}
如果(n==1且存在)计数(n-1,0);
}
int main()
{
ll n;cin>>n;
如果(n==1){

我相信你的问题之一是你在重新计算东西

以n=4为例,[0,3]中x的计数(3,x)被调用3次

但是,如果制作了一个std::map,则可以保存(n,present)对的值,并且只计算每个值一次

这将占用更多空间。完成后,地图将是4*(n-1)大。这可能仍然太大,无法容纳10^9

您可以做的另一件事是多线程。每个对count的调用都会引发它自己的线程。如果您决定使用它,那么在更改全局计数和std::map的状态时,您需要注意线程安全

编辑: 计算[1,n-1]中n的计数(n,x)一次,然后计算[0,3]中的计数[n,0]=a*计数(n-1,1)+b*计数(n-1,2)+c*计数(n-1,3)


如果你能找出a,b,c被赋予n的模式,或者甚至是n-1情况下的a,b,c的模式,那么你就可以很容易地解决这个问题。

任何时候你构建了一个递归,并且超过了时间复杂度,你必须理解递归很可能就是问题所在

最好的解决方案是不使用递归

看看你得到的结果:

  • 三,
  • 六,
  • 二十一,
  • 六十
  • 183
  • 546
  • 1641年
  • 4920
  • ⋮      ⋮

    虽然可能很难找到前两个术语的模式,但以后会更容易

    每个术语大约是上一个术语的3倍,或者更准确地说,

    现在您可以为它编写一个for循环:

    for(int i = 0; i < n-1; i++)
    {
        count_moves = count_moves * 3 + std::pow(-1, i) * 3;
    }
    
    此外,您甚至可以将其构建到通用术语公式中,以消除for循环: 或在代码中:

    count_moves = (pow(3, n) + (n % 2 * 2 - 1) * -3) / 4;
    

    但是,您无法摆脱
    pow()
    这一次,否则您将不得不为此编写一个循环。

    代码没有编译,您正在对
    mod
    进行去编译?您的计数函数也返回值,但您忽略了它。作为一个微观优化,您可以将
    %4
    替换为
    &3
    %
    操作通常涉及除法,这是非常昂贵的e、 编译器可能会识别模式并进行更改,具体取决于优化级别和编译器的功能。您肯定需要提高键入技能,以便不需要使用缩写宏。这些宏实际上会延长编译时间(因为它必须在编译之前执行所有这些替换,而不是解析已知关键字)。宏也使读取代码变得困难。我们查看
    ll
    ,然后确定它是您创建的类型还是宏。如果您使用
    long
    ,我们理解声明不会有问题。根据经验,超过了时间限制(TLE)错误,通常意味着您的实现或算法太慢,需要寻找更快的算法。优化不会提供足够的速度,请使用其他算法。
    count_moves = (pow(3, n) + (n % 2 * 2 - 1) * -3) / 4;