算法思想:维护而非重新计算
2015-09-13 12:29
225 查看
算法思想:维护而非重新计算
一、引入
先介绍一道简单的题目:给你两个同样长度的序列,请你判断通过一个映射,是否可以将第一个序列转化成第二个序列。序列中的每个元素都是一个大写字母。例如ADDDA可以以A->C,D->F的映射转化为CFFFC;但是ABC无论如何也转化不成ENE。
看到这道题,直觉算法是这样的:对序列1中的元素遍历,找到序列1中该元素后面与该元素一样的所有位置,测试序列2中同样位置的元素是不是也都相同。
这样的算法毫无疑问是可以完成任务的,但是其复杂度为O(n^2),有很多元素都被重复计算过多遍。于是我们应该怎样改进算法呢?这就要用到维护而非重新计算的思想了。当经过序列1中某个元素第一次出现的位置时,我们能知道这时序列1中的元素为X,序列2中的元素为Y。如果这两个序列之间存在映射变换关系的话,X->Y是必定存在的映射,于是我们把这个映射记录下来。遇到序列1中又一次出现X时,我们对X进行映射,看序列2中该位置是不是Y。如果是,则继续;如果不是,则该序列必不能匹配。
bool check(char* fir,char* sec,int size) { int map[26]; for(int i=0;i<26;++i) map[i]=INT_MIN; for(int i=0;i<size;++i) { if(map[sec[i]-'A']==INT_MIN) map[sec[i]-'A']=fir[i]-sec[i]; else if(fir[i]-sec[i]- map[sec[i]-'A']!=0) return false; } return true; }
这样算法的复杂度就成了O(n),是一个很大的突破。
二、对首选梯度上升法的改进
为什么要介绍这种算法思想呢?因为它对上一章讲过的梯度上升法可以有很大的改进作用。上一章提到evaluate函数是算法的瓶颈之一,而我们就用维护而非重新计算的思想改进它。在calculate函数中,为了找到更优化的棋局,我们对每一个改变过的皇后调用一次evaluate函数,而每次evaluate函数都是重新计算冲突数,这样就浪费了很多信息。假设我们已知第i列的皇后在位置j时,评估值为N,有没有办法利用这些信息,更快地计算出这个皇后移到位置k时的评估值M呢?有办法的。
我们先计算出皇后i在位置j时,与这个皇后冲突的其它皇后的数量f(i,j),这需要对所有皇后的位置过一遍,时间复杂度为O(n)。在总的评估值中减去这个数,即为这个列没有皇后时的冲突数。同理可得,计算皇后i在位置k时由它引起的冲突数f(i,k),即为这个列没有皇后时的冲突数。因此,M=N-f(i,j)+f(i,k),这样我们就得到了新的评估值。而这个evaluate操作的时间复杂度也就从O(n*n)变为了O(n+n)。
以下是改进过的首选梯度上升法:
#include<iostream>
#include<ctime>
using namespace std;
class queen
{
private:
int size;
int eva_now;
int *list;
void init()
{
for(int i=0;i<size;++i)
list[i]=rand()%size;
eva_now=evaluate(list);
}
int eva_by_x(int *li,int minx,int miny)
{
int eva=0;
for(int x=0;x<size;++x)
{
if(x==minx)
continue;
else if(li[x]==miny)
eva++;
else if(abs(miny-li[x])==abs(minx-x))
eva++;
}
return eva;
}
int evaluate(int *li)
{
int eva=0,minx,miny,x;
for(minx=0;minx<size;++minx)
{
miny=li[minx];
for(x=minx+1;x<size;++x)
{
if(x==minx)
continue;
else if(li[x]==miny)
eva++;
else if(abs(miny-li[x])==abs(minx-x))
eva++;
}
}
return eva;
}
bool calculate()
{
if(eva_now==0)
return true;
int x,y,recoardy,recoardeva=eva_now;
int tmp;
int course_x=0;
bool change=false;
for(x=0;x<size;++x)
{
recoardy=list[x];
course_x=eva_by_x(list,x,list[x]);
for(y=0;y<size;++y)
{
if(y==recoardy)
continue;
else
{
tmp=eva_by_x(list,x,y);
if(tmp<course_x)
{
list[x]=y;
eva_now=eva_now-course_x+tmp;
return true;
}
}
}
}
return false;
}
public:
void output()
{
for(int i=0;i<size;++i)
cout<<list[i]<<endl;
}
bool start()
{
if(size==-1)
return false;
for(int i=0;i<1000000;++i)
{
if(eva_now==0)
return true;
else
{
if(calculate())
continue;
else
init();
}
}
return false;
}
bool start(int &stp,int &res)
{
stp=0;
res=0;
if(size==-1)
return false;
for(int i=0;i<100000;++i)
{
stp++;
if(eva_now==0)
return true;
else
{
if(calculate())
continue;
else
{
init();
res++;
}
}
}
return false;
}
queen()
{
srand(clock());
size=-1;
list=NULL;
}
bool setsize(int n)
{
if(size!=-1)
delete[] list;
list=new int
;
if(!list)
return false;
size=n;
init();
}
queen(int _size):size(_size)
{
srand(clock());
list=new int[size];
init();
}
~queen()
{
if(size!=-1)
delete[] list;
}
};
以下是这个算法在我的破笔记本电脑上的运行结果:
10 queens : 0ms , used 12 steps, reset 0 times
11 queens : 4ms , used 128 steps, reset 13 times
12 queens : 1ms , used 23 steps, reset 2 times
13 queens : 4ms , used 70 steps, reset 6 times
14 queens : 4ms , used 63 steps, reset 4 times
15 queens : 14ms , used 210 steps, reset 17 times
16 queens : 91ms , used 1035 steps, reset 73 times
17 queens : 6ms , used 62 steps, reset 3 times
18 queens : 171ms , used 1656 steps, reset 96 times
19 queens : 272ms , used 2401 steps, reset 141 times
20 queens : 232ms , used 1765 steps, reset 97 times
21 queens : 238ms , used 1513 steps, reset 82 times
22 queens : 75ms , used 428 steps, reset 21 times
23 queens : 75ms , used 379 steps, reset 16 times
24 queens : 5ms , used 20 steps, reset 0 times
25 queens : 160ms , used 645 steps, reset 26 times
26 queens : 317ms , used 1072 steps, reset 42 times
27 queens : 52ms , used 153 steps, reset 5 times
28 queens : 186ms , used 498 steps, reset 18 times
29 queens : 1305ms , used 3287 steps, reset 120 times
30 queens : 186ms , used 404 steps, reset 13 times
31 queens : 360ms , used 679 steps, reset 23 times
32 queens : 2173ms , used 5210 steps, reset 176 times
33 queens : 1241ms , used 3015 steps, reset 97 times
34 queens : 220ms , used 383 steps, reset 11 times
35 queens : 2176ms , used 3308 steps, reset 100 times
36 queens : 1363ms , used 2037 steps, reset 61 times
37 queens : 745ms , used 1015 steps, reset 27 times
38 queens : 8228ms , used 10018 steps, reset 280 times
39 queens : 282ms , used 315 steps, reset 7 times
40 queens : 651ms , used 742 steps, reset 18 times
41 queens : 1600ms , used 1518 steps, reset 38 times
42 queens : 675ms , used 628 steps, reset 14 times
43 queens : 6719ms , used 5810 steps, reset 142 times
44 queens : 4395ms , used 3569 steps, reset 85 times
45 queens : 3283ms , used 2452 steps, reset 55 times
46 queens : 11724ms , used 8237 steps, reset 186 times
47 queens : 3918ms , used 2589 steps, reset 58 times
48 queens : 1404ms , used 849 steps, reset 17 times
49 queens : 5317ms , used 3187 steps, reset 66 times
50 queens : 3786ms , used 2059 steps, reset 41 times
51 queens : 8266ms , used 4349 steps, reset 87 times
52 queens : 1950ms , used 954 steps, reset 18 times
53 queens : 23956ms , used 11443 steps, reset 222 times
54 queens : 2028ms , used 1078 steps, reset 19 times
55 queens : 705ms , used 386 steps, reset 6 times
56 queens : 8508ms , used 3983 steps, reset 72 times
57 queens : 1305ms , used 489 steps, reset 8 times
58 queens : 12473ms , used 4565 steps, reset 80 times
59 queens : 1989ms , used 681 steps, reset 11 times
60 queens : 91447ms , used 30809 steps, reset 525 times
61 queens : 5207ms , used 2178 steps, reset 35 times
62 queens : 32519ms , used 10533 steps, reset 172 times
63 queens : 7421ms , used 2106 steps, reset 32 times
64 queens : 18309ms , used 5395 steps, reset 84 times
65 queens : 35677ms , used 9269 steps, reset 147 times
66 queens : 10190ms , used 2745 steps, reset 41 times
67 queens : 15633ms , used 3731 steps, reset 56 times
68 queens : 2703ms , used 612 steps, reset 8 times
69 queens : 15742ms , used 3464 steps, reset 50 times
70 queens : 2843ms , used 633 steps, reset 8 times
71 queens : 16286ms , used 3328 steps, reset 46 times
72 queens : 31098ms , used 6537 steps, reset 92 times
73 queens : 184579ms , used 36221 steps, reset 500 times
74 queens : 78013ms , used 14455 steps, reset 197 times
75 queens : 27006ms , used 5446 steps, reset 71 times
76 queens : 29666ms , used 6900 steps, reset 90 times
77 queens : 20713ms , used 3276 steps, reset 41 times
78 queens : 6867ms , used 1419 steps, reset 17 times
79 queens : 23483ms , used 3491 steps, reset 43 times
80 queens : 24183ms , used 3454 steps, reset 42 times
81 queens : 10245ms , used 1395 steps, reset 17 times
82 queens : 144705ms , used 20220 steps, reset 246 times
83 queens : 98812ms , used 12632 steps, reset 151 times
84 queens : 71014ms , used 8723 steps, reset 102 times
85 queens : 6961ms , used 829 steps, reset 9 times
86 queens : 5553ms , used 607 steps, reset 6 times
87 queens : 33738ms , used 3781 steps, reset 42 times
88 queens : 40079ms , used 4293 steps, reset 47 times
89 queens : 91678ms , used 10334 steps, reset 115 times
90 queens : 204185ms , used 22628 steps, reset 250 times
91 queens : 101065ms , used 10678 steps, reset 117 times
92 queens : 153650ms , used 14632 steps, reset 159 times
93 queens : 74092ms , used 7643 steps, reset 81 times
94 queens : 128694ms , used 12199 steps, reset 130 times
95 queens : 301043ms , used 26924 steps, reset 280 times
96 queens : 158951ms , used 13989 steps, reset 145 times
97 queens : 195779ms , used 15854 steps, reset 163 times
98 queens : 132589ms , used 11876 steps, reset 120 times
99 queens : 147190ms , used 12100 steps, reset 121 times
100 queens : 10394ms , used 851 steps, reset 7 times
可以看到,效率有了很大的提高。但是仍然不堪大用,可以看到这有陷入局部极值次数太多的原因。如果采用模拟退火算法,可以有更好的效果。
相关文章推荐
- android 代码实现控件之间的间距
- [Android]在代码里运行另一个程序的方法
- 肯特·贝克:改变人生的代码整理魔法
- 网页恶意代码的预防
- 动易2006序列号破解算法公布
- 高手写的Tracer-Flash代码调试类代码下载
- CSS代码缩写技巧
- 非主流Q-zOne代码代码搜集第1/2页
- Ruby实现的矩阵连乘算法
- CreateWeb.vbs 代码
- C#插入法排序算法实例分析
- Lua中编译执行代码相关的函数详解
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- 对学Oracle数据库初学者的开场篇
- C#实现的算24点游戏算法实例分析
- 更有效率的css代码编写第1/3页