【问题标题】:How can I improve this algorithm to prevent TLE is SPOJ submission?如何改进此算法以防止 TLE 是 SPOJ 提交?
【发布时间】:2012-04-13 19:09:13
【问题描述】:

我正在尝试解决以下问题: http://www.spoj.pl/problems/TRIP/

我使用 C++ 中的 DP(动态编程)编写了一个解决方案(代码发布在下面)。但我得到 TLE(超过时间限制)。如何优化我的代码?

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>

using namespace std;
string a,b;
vector<string> v;
int dp[85][85];

void filldp()
{
    for(int i = 0; i <= a.length(); i++)
        dp[i][0] = 0;
    for(int i = 0; i <= b.length(); i++)
        dp[0][i] = 0;   

    for(int i = 1; i <= a.length(); i++)
        for(int j = 1; j<= b.length(); j++)
        if(a[i-1] == b[j-1])
            dp[i][j] = dp[i-1][j-1] + 1;
        else
            dp[i][j] = max(dp[i-1][j], dp[i][j-1]); 
}

vector<string> fillv(int i, int j)
{
    vector<string> returnset;
    if(i == 0 || j == 0)
    {   returnset.push_back("");
        return returnset;
    }

    if(a[i-1] == b[j-1])
        { 
          vector<string> set1 = fillv(i-1,j-1);
          for(int k = 0; k < set1.size(); k++)
          { 
            returnset.push_back(set1[k] + a[i-1]);
         }  
          return returnset;
        }

    else
        {
            if(dp[i][j-1] >= dp[i-1][j])
            {
                vector<string> set1 = fillv(i,j-1);
                returnset.insert(returnset.end(), set1.begin(), set1.end());
            }

            if(dp[i-1][j] >= dp[i][j-1])
            {
                vector<string> set2 = fillv(i-1,j);
                returnset.insert(returnset.end(), set2.begin(), set2.end());
            }

            return returnset;

        }       

}

void output()
{
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    for(int i = 0; i < v.size(); i++)
        cout << v[i] << endl;   
    cout << endl;       
}

int main()
{
    int T;
    cin >> T;

    while(T--)
    {
        memset(dp,-1,sizeof(dp));
        v.clear();
        cin >> a >> b;
        filldp();
        v = fillv(a.length(), b.length());
        output();
    }
    return 0;
}

我的猜测是,有很多数据结构的传递是可以避免的,但我无法确切地弄清楚如何。

【问题讨论】:

  • 什么是 TLE?三个字母的回避?如果您不要求受访者熟悉特定亚文化的行话,您将获得更多/更好的答案。

标签: c++ algorithm data-structures dynamic-programming


【解决方案1】:

您做的第一件事是使用 cin 和 cout,它们非常慢。切勿将 cin 和 cout 用于竞赛编程!我只是通过将 cin/cout 更改为 scanf/printf 从 TLE 转到 AC。

【讨论】:

  • 另一种选择是将ios::sync_with_stdio(false); 添加到您的代码中。
  • 你能解释一下是什么吗?
  • TLE 是在线法官给您的答案之一。在线法官有一组问题:您选择其中一个,编写解决方案,然后发送代码。法官编译解决方案,运行它,提供输入数据并分析程序产生的输出数据。然后,它给你一个答案:AC(意思是接受)意味着你的解决方案是好的:它编译正确,并计算出正确的答案。 TLE 意味着你的解太慢了:当裁判运行它时,它未能在时间限制之前计算出解。您应该尝试 SPOJ (www.spoj.pl) 或 COJ (coj.uci.cu)。
  • 哦,抱歉,忘记提到 TLE 已超出时间限制。其他常见的判断有WA(错误答案:你的程序没有输出输入数据的正确答案)、CE(编译错误,不用解释)、MLE(超出内存限制:你的程序使用了太多内存)和PE(演示错误:您的程序输出正确的数据,但格式错误)。
【解决方案2】:

当您知道答案数量的最大大小时,最好使用数组而不是向量 因为它比向量快得多。 (“至少有一次这样的旅行,但从不超过 1000 次不同的旅行”)

函数fillv在代码中浪费了大量时间。因为它在运行时获得了大量空间并释放它(因为fillv 函数的本地空间)。最好使用全局答案。

对于输入和输出来完成“Gandalf the Grey”的回答,如果你喜欢使用 cin 和 cout ,最好使用 std::ios::sync_with_stdio(false); (加快你的 io 运行时间)但是 printf 和 scanf 比这 。

【讨论】:

  • 关于vector 和已知大小:只需调用vector::reserve 来预分配内存。当然,有时你真的想要堆栈分配内存,所以使用std::array
【解决方案3】:

您可以通过使用fread()fread_unlocked()(如果您的程序是单线程的)获取输入来大大减少执行时间。锁定/解锁一次输入流所花费的时间可以忽略不计,因此请忽略它。

代码如下:

#include <iostream>

int maxio=1000000;
char buf[maxio], *s = buf + maxio;

inline char getc1(void)
{
   if(s >= buf + maxio) { fread_unlocked(buf,sizeof(char),maxio,stdin); s = buf; }
   return *(s++);
}
inline int input()
{
   char t = getc1();
   int n=1,res=0;
   while(t!='-' && !isdigit(t)) t=getc1(); if(t=='-')
   {
      n=-1; t=getc1();
   }
   while(isdigit(t))
   {
     res = 10*res + (t&15);
     t=getc1();
   }
   return res*n;
}

这是在C++ 中实现的。在C 中,您不需要包含iostream,函数isdigit() 是隐式可用的。

您可以通过调用getc1() 将输入作为字符流,并通过调用input() 将整数输入。

使用fread() 背后的整个想法是一次获取大量输入。调用scanf()/printf(),反复占用宝贵的时间来锁定和解锁流,这在单线程程序中完全是多余的。

还要确保maxio 的值使得所有输入只能在几次“往返”中获取(在这种情况下最好是一次)。根据需要对其进行调整。这种技术在编程比赛中非常有效,可以在执行时间方面超越对手。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 1970-01-01
    • 2011-04-19
    • 2012-05-26
    相关资源
    最近更新 更多