昨天在PKU上做了一题2187,限时3s。
算法主要耗时在多次求不同整数的平方。
当用pow函数求时,超时;
而直接乘才232ms。
相差也太大了吧。
于是就写了一段代码来测试pow的性能
首先产生10000个随机整数,然后重复1000次求整数的平方
#include <iostream>
#include <cmath>
#include <ctime>

using Namespace stdnamespace std;
const int MAX = 10000;
int a[MAX];
int main()
{
int i, j, n = MAX;
int rep = 1000; //重复次数
clock_t beg, end;
for(i = 0; i < n; i++)
a[i] = rand() % 20000 - 10000; //-10000 <= a[i]< 10000

cout<<"test a[i]*a[i]"<<endl;
beg = clock();
for(j = 0; j < rep; j++)
for(i = 0; i < n; i++)
a[i] * a[i];
end = clock();
cout<<"time: "<<end - beg<<"ms"<<endl;
cout<<"test pow(a[i], 2.0)"<<endl;
beg = clock();
for(j = 0; j < rep; j++)
for(i = 0; i < n; i++)
pow(a[i], 2.0);
end = clock();
cout<<"time: "<<end - beg<<"ms"<<endl;

return 0;
}

下面是测试结果:
test a[i]*a[i]
time: 31ms
test pow(a[i], 2.0)
time: 2828ms
所以下次遇到类似情况不再用pow函数了……
posted @
2007-08-25 20:16 beyonlin 阅读(5747) |
评论 (6) |
编辑 收藏
在做PKU2762时,需要建邻接表。
于是按部就班写了下面一个插入边到邻接表中的函数:
const int VMAX = 1010;
typedef struct Graph
{
int vex;
Graph* next;
}Graph;
Graph ArcGraph[VMAX];
void insert(int u, int v)
{
Graph* t = new Graph;
Graph* p = ArcGraph[u].next;
t->vex = v;
t->next = p;
ArcGraph[u].next = t;
}
完成完整的程序提交上去,得到结果
Memory:25796K Time:375MS
Language:C++ Result:Accepted
再对比别人的程序
Memory:296K Time:109MS
无论是时间还是空间都相差很大。
于是就考虑怎么优化自己的程序。
第一个问题:规模只有1000,为什么会用那么多内存呢?
仔细一想数据是多case的,每次插入新节点时都要动态创建一个节点。
一来动态创建耗时间,二来每个case结束的邻接表中的节点没有释放,故耗费大量内存。
然后就想到了下面的算法,首先初始化一块内存Graph use[100*VMAX];这样每次需要新节点时,
就从use中获取。如果use使用完毕就再动态创建。
依此算法优化后,得到的结果比较满意
Memory:1000K Time:218MS
Language:C++ Result:Accepted
const int VMAX = 1010;
typedef struct Graph
{
int vex;
Graph* next;
}Graph;
Graph ArcGraph[VMAX];
Graph use[100*VMAX];
int size = 0;
void insert(int u, int v)
{
Graph* t;
if(size < 100*VMAX)
{
t = &use[size];
size++;
}
else t = new Graph;
Graph* p = ArcGraph[u].next;
t->vex = v;
t->next = p;
ArcGraph[u].next = t;
}
posted @
2007-08-13 00:29 beyonlin 阅读(1541) |
评论 (0) |
编辑 收藏
发现用stl中的bitset求子集树只要短短的几行代码
#include<iostream>
#include<bitset>

using Namespace stdnamespace std;
const int n = 4;
int main()
{
for(int i = 0; i < (1 << n); i++)
{
bitset<n> bit(i);
for(int j = bit.size() - 1; j >= 0; j--)
cout<<bit[j];
cout<<endl;
}
return 0;
}

n个元素有2^n个子集,
i从0到2^n - 1,
把它换算成二进制就分别对应一个子集。
posted @
2007-07-23 15:56 beyonlin 阅读(1073) |
评论 (0) |
编辑 收藏
以前求子集树都是用回溯法,
今天在topcoder做SRM时学到一种求子集树的新方法:位运算。
第一重循环是枚举所有子集,共2^n个,即1 << n个
第二重循环求集合所有j个元素的值,0或1。
求一下1 & (1 << j)的值就可以知道它的原理。
#include<iostream>

using Namespace stdnamespace std;
const int n = 4;
int x[n];
//回溯法
void backtrack(int t)
{
if(t >= n)
{
for(int i = 0; i < n; i++)
cout<<x[i];
cout<<endl;
}
else
{
for(int i = 0; i <= 1; i++)
{
x[t] = i;
backtrack(t + 1);
}
}
}
//位运算
void bitOperate()
{
for(int i = 0; i < (1 << n); i++)
{
for(int j = 0; j < n; j++)
{
if( (i & (1 << j) ) == 0)
x[j] = 0;
else
x[j] = 1;
}
for(int j = 0; j < n; j++)
cout<<x[j];
cout<<endl;
}
}
int main()
{
backtrack(0);
cout<<endl;
bitOperate();
return 0;
}

posted @
2007-07-22 02:59 beyonlin 阅读(1753) |
评论 (0) |
编辑 收藏
#include<iostream>
using namespace std;
const int MAXV = 10000; //素数表范围
bool flag[MAXV+1]; //标志一个数是否为素数
int prime[MAXV+1]; //素数表,下标从0开始
int size; //素数个数
void genPrime(int max)
{
memset(flag, true, sizeof(flag));
for(int i = 2; i <= max / 2; i++)
{
if(flag[i])
{
for(int j = i << 1 ; j <= max; j += i)
{
flag[j] = false;
}
}
}
for(int i = 2 ; i <= max; i++)
{
if(flag[i])
{
prime[size++] = i;
}
}
}
int main()
{
genPrime(MAXV);
return 0;
}

posted @
2007-05-18 16:13 beyonlin 阅读(2653) |
评论 (2) |
编辑 收藏