我解决了一个集合操作的问题,比如上界,迭代器解引用等等,它在20秒内就解决了。一般的问题是我在一组数字上迭代(i*(i-1)/2)直到它小于2 * 10^5,然后完成一个DP向量。所以在我的算法中,对于每个数字“x”我得到上界,“up”,然后从头开始迭代这些数字直到达到“up”。该解决方案做同样的事情,但是它不运行upper_bound和解引用,而是直接计算i*(i-1)/2,这是我先前计算并存储在vset中的。两种算法的运算次数几乎相同,大约为8010^6,这不是一个超级大的数字。但是我的代码需要20秒,解决方案需要2秒。
请看看我的代码,让我知道如果你需要更多的信息:
1-vset具有600个数字,其全部是i(i-1)/2形式的数字;小于2*10^5
2-vset在增加时已排序
3-两种算法中最终矢量“v”完全相同
4-cnt,两者的操作数几乎相同。80,000,000
5-你可以用n = 199977测试代码。
6-在我的电脑上,corei 7 32 G内存,需要20秒,在服务器上接受大约200毫秒,这对我来说很奇怪。
typedef long long int llint;
int n; cin >> n;
vector<llint> v(n+1, INT_MAX);
llint p = 1;
llint node = 2;
llint cnt = 0;
for (int i = 1; i <= n; i++)
{
if (v[i] == INT_MAX)
{
for (int s = 1; (s * (s - 1)) / 2 <= i; ++s)
v[i] = min(v[i], v[i - (s * (s - 1)) / 2] + s) , cnt++;
}
else cnt ++ ;
}
cout << cnt << endl; // works in less than 2 seconds
第二个解决方案需要20秒。
typedef long long int llint;
int n; cin >> n;
vector<llint> v(n+1, INT_MAX);
llint p = 1;
llint node = 2;
vector<int> vset;
while (p <= n) // only 600 numbers
{
v[p] = node;
vset.push_back(p);
node++;
p = node * (node - 1) / 2;
}
llint cnt = 0;
for (int i = 1; i <= n; i++)
{
if (v[i] == INT_MAX)
{
auto up = upper_bound(vset.begin(), vset.end(), i);
for (auto it = vset.begin(); it != up; it++) // at most 600 iteration
{
cnt++;
int j = *it;
v[i] = min(v[j] + v[i - j], v[i]);
}
}
else cnt ++ ;
}
cout << cnt << endl; // cnt for both is around 84,000,000
所以这个问题是关于一些我想不明白的事情:这里的哪个操作是昂贵的?**遍历迭代器?取消引用迭代器?这里没有更多的区别,但是时间是十倍。**谢谢
1条答案
按热度按时间eoxn13cs1#
感谢所有评论并帮助我解决这个问题的人。我意识到我性能缓慢的原因是调试模式。所以我把它改为发布模式,它在不到2秒的时间内工作。有一个similar question,可能会帮助你更多。我在Windows 10上使用Visual Studio C++