我正在尝试在线评判的经典子集和问题。然而,这次的差异是n <= 30,因此最大操作可以达到30 * 2 ^ 30。我已经有了一些工作代码。但是,程序的时间限制是1秒,我的程序在0.5到1.1秒之间徘徊。这导致了TLE,尽管我尽力加快我的代码速度。你们有什么提示我可以如何进一步加快和优化我的代码吗?提前致谢。
#include <iostream>
#include <cstdio>
using namespace std;
unsigned power(unsigned x, unsigned y){ //pow function
unsigned sum=x;
for (int i=1;i<=y-1;i++)
sum*=x;
return sum;
}
int main(){
unsigned t, n, p, sum, sum2, tmpsum=0;
unsigned bars[32];
bool found;
scanf("%u", &t);
while (t--){
tmpsum=0;
found=false;
scanf("%u %u", &n, &p);
for (int i=0;i<p;i++){
scanf("%u",&bars[i]);
tmpsum+=bars[i];
}
if (tmpsum<n)found=false;
unsigned end=power(2,p)-1; //counting from the end and from the start
for (unsigned i=0;i<power(2,p)&&tmpsum>=n;i++){ //counting from 1 to 2^n in binary
sum=0;
sum2=0;
for (unsigned j=0;j<p;j++){
if (i&(1<<j))
sum+=bars[j];
if (end&(1<<j)) //counting from the end and start at the same time
{sum2+=bars[j];end--;}
}
if (sum==n||sum2==n)
{found=true;break;}
}
cout<<(found==true?"YES":"NO")<<endl;
}
}
答案 0 :(得分:3)
将power(2,p)
移出循环。
for (unsigned i=0;i<power(2,p)&&tmpsum>=n;i++)
^^^^
答案 1 :(得分:3)
使用位移计算两度。
答案 2 :(得分:2)
编写丑陋的代码并不会使代码更快,将语句分成不同的行,即用
替换{sum2+=bars[j];end--;}
{
sum2 += bars[j];
--end;
}
关于这个问题:你的主要时间损失可能在这里:
for (unsigned i=0;i<power(2,p)&&tmpsum>=n;i++){
除非你有一个特别好的编译器,否则在循环的每个循环中计算power(2, p)
一次,这是完全不需要的。预先计算它。
int pow2p = power(2, p);
for (unsigned i=0;i<pow2p&&tmpsum>=n;i++){
此外,以这种方式执行2的功能非常慢,因此请改用<<
(1<<p == power(2, p)
)。
修改由于这已被接受,我会从其他答案/评论中收集一些小点:
正如Nim指出的那样,tmpsum>=n
检查不需要在每个循环中完成,因为n
和tmpsum
在循环期间都不会发生变化。
正如Karthik T指出的那样,if (tmpsum<n)found=false;
行是多余的,此时found
永远不会是false
。
答案 3 :(得分:1)
除了别人所说的,Avoid Branching。 例如:
if (i&(1<<j))
sum+=bars[j];
可以写成
sum+=bars[j] * ((i&(1<<j))>>j);
当然,它使得阅读代码变得更加难以阅读。
答案 4 :(得分:0)
if (tmpsum<n)found=false;
此行无效,found
已经false
。
1<<j
正在计算两次,可以通过存储结果减少到一次。
答案 5 :(得分:0)
对于初学者,您可以将power(2,p)
移出for循环
for (unsigned i=0, end=power(2,p); i<end && tmpsum>=n; i++)
答案 6 :(得分:-1)
将sum和sum2定义为寄存器变量。
注册无符号和,sum2;