wij算法
㈠ 图的存储结构——所存储的信息有哪些
一、邻接矩阵存储方法
邻接矩阵是表示顶点之间相邻关系的矩阵。
设G=(V,E)是具有n(n>0)个顶点的图,顶点的顺序依次为0~n-1,则G的邻接矩阵A是n阶方阵,其定义如下:
(1)如果G是无向图,则:
A[i][j]=1:若(i,j)∈E(G) 0:其他
(2)如果G是有向图,则:
A[i][j]=1:若<i,j>∈E(G) 0:其他
(3)如果G是带权无向图,则:
A[i][j]= wij :若i≠j且(i,j)∈E(G) 0:i=j ∞:其他
(4)如果G是带权有向图,则:
A[i][j]= wij :若i≠j且<i,j>∈E(G) 0:i=j∞:其他
注意:带权图和不带权图表示的元素类型不同。
带权图(不论有向还是无向图)A[i][j]用double表示,不带权图(不论有向还是无向图)A[i][j]用int表示。
用一维数组G[ ]存储有4个顶点的无向图如:G[ ] = { 0, 1, 0, 1, 1, 0, 0, 0, 1, 0 }
则顶点2和顶点0之间是有边的。
如:
邻接矩阵的特点如下:
(1)图的邻接矩阵表示是唯一的。
(2)无向图的邻接矩阵一定是一个对称矩阵。因此,按照压缩存储的思想,在具体存放邻接矩阵时只需存放上(或下)三角形阵的元素即可。
(3)不带权的有向图的邻接矩阵一般来说是一个稀疏矩阵。因此,当图的顶点较多时,可以采用三元组表的方法存储邻接矩阵。
(4)对于无向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点的度。
(5)对于有向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点的出度(或入度)。
(6)用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连。但是,要确定图中有多少条边,则必须按行、按列对每个元素进行检测,所花费的时间代价很大。这是用邻接矩阵存储图的局限性。
邻接矩阵的数据类型定义如下:
#define MAXV <最大顶点个数>
typedef struct
{ int no; //顶点编号
InfoType info; //顶点其他信息
} VertexType; //顶点类型
typedef struct //图的定义
{ int edges[MAXV][MAXV]; //邻接矩阵
int n,e; //顶点数,弧数
VertexType vexs[MAXV]; //存放顶点信息
} MGraph; //图的邻接矩阵表示类型
二、 邻接表存储方法
图的邻接表存储方法是一种顺序分配与链式分配相结合的存储方法。
在邻接表中,对图中每个顶点建立一个单链表,第i个单链表中的节点表示依附于顶点i的边(对有向图是以顶点i为尾的边)。每个单链表上附设一个表头节点。
其中,表节点由三个域组成,adjvex指示与顶点i邻接的点在图中的位置,nextarc指示下一条边或弧的节点,info存储与边或弧相关的信息,如权值等。
表头节点由两个域组成,data存储顶点i的名称或其他信息,firstarc指向链表中第一个节点。
typedef struct ANode
{ int adjvex; //该边的终点编号
struct ANode *nextarc; //指向下一条边的指针
InfoType info; //该边的相关信息
} ArcNode; //边表节点类型
typedef struct Vnode
{ Vertex data; //顶点信息
ArcNode *firstarc; //指向第一条边
} VNode; //邻接表头节点类型
typedef VNode AdjList[MAXV]; //AdjList是邻接表类型
typedef struct
{ AdjList adjlist; //邻接表
int n,e; //图中顶点数n和边数e
} ALGraph; //完整的图邻接表类型
邻接表的特点如下:
(1)邻接表表示不唯一。这是因为在每个顶点对应的单链表中,各边节点的链接次序可以是任意的,取决于建立邻接表的算法以及边的输入次序。
(2)对于有n个顶点和e条边的无向图,其邻接表有n个顶点节点和2e个边节点。显然,在总的边数小于n(n-1)/2的情况下,邻接表比邻接矩阵要节省空间。
(3)对于无向图,邻接表的顶点i对应的第i个链表的边节点数目正好是顶点i的度。
(4)对于有向图,邻接表的顶点i对应的第i个链表的边节点数目仅仅是顶点i的出度。其入度为邻接表中所有adjvex域值为i的边节点数目。
例, 给定一个具有n个节点的无向图的邻接矩阵和邻接表。
(1)设计一个将邻接矩阵转换为邻接表的算法;
(2)设计一个将邻接表转换为邻接矩阵的算法;
(3)分析上述两个算法的时间复杂度。
解:
(1)在邻接矩阵上查找值不为0的元素,找到这样的元素后创建一个表节点并在邻接表对应的单链表中采用前插法插入该节点。
void MatToList(MGraph g,ALGraph *&G)
//将邻接矩阵g转换成邻接表G
{ int i,j,n=g.n; ArcNode *p; //n为顶点数
G=(ALGraph *)malloc(sizeof(ALGraph));
for (i=0;i<n;i++) //给所有头节点的指针域置初值
G->adjlist[i].firstarc=NULL;
for (i=0;i<n;i++) //检查邻接矩阵中每个元素
for (j=n-1;j>=0;j--)
if (g.edges[i][j]!=0)
{ p=(ArcNode *)malloc(sizeof(ArcNode));
//创建节点*p
p->adjvex=j;
p->nextarc=G->adjlist[i].firstarc;
//将*p链到链表头
G->adjlist[i].firstarc=p;
}
G->n=n;G->e=g.e;
}
(2)在邻接表上查找相邻节点,找到后修改相应邻接矩阵元素的值。
void ListToMat(ALGraph *G,MGraph &g)
{ int i,j,n=G->n;ArcNode *p;
for (i=0;i<n;i++)
{ p=G->adjlist[i].firstarc;
while (p!=NULL)
{ g.edges[i][p->adjvex]=1;
p=p->nextarc;
}
}
g.n=n;g.e=G->e;
}
(3)算法1的时间复杂度均为O(n2)。算法2的时间复杂度为O(n+e),其中e为图的边数。
㈡ 贪心算法
平面点集三角剖分的贪心算法要求三角剖分后边的总长度尽可能小。算法的基本思想是将所有的两点间距离从小到大排序,依次序每次取一条三角剖分的边,直至达到要求的边数。以下是两种贪心算法的主要步骤。
3.2.2.1 贪心算法1
第一步:设置一个记录三角剖分中边的数组T。
第二步:计算点集S中所有点对之间的距离d(pi,pj),1≤i,j≤n,i≠j,并且对距离从小到大进行排序,设为d1,d2,…,dn(n-1)/2,相应的线段记为e1,e2,…,en(n-1)/2,将这些线段存储在数组E中。
第三步:从线段集E中取出长度最短的边e1存到T中作为三角剖分的第一条边,此时k=1。
第四步:依次从E中取出长度最短的边ek,与T中已有的边进行求交运算,如果不相交则存到T中,并从E中删除ek。这一步运行到S中没有边为止,即至k=n(n-1)/2。
第五步:输出T。
该算法中,第二步需要计算n(n-1)/2次距离,另外距离排序需要O(n2lgn)次比较。T中元素随第四步循环次数的增加而增加,因此向T中加入一条新边所需要的判定两条线段是否相交的次数也随之增加。如果第四步的前3n-6次循环后已经构成点集的三角剖分,那么第四步循环所需要的判定两条线段是否相交的次数为
1+2+…+3n-7+(3n-6)×(n(n-1)/2-(3n-6))=O(n3)
在常数时间内可以判定两条线段是否相交,因此该算法的时间复杂性为O(n3)。
3.2.2.2 贪心算法2
第一步:求点集的凸壳,设凸壳顶点为p1,p2,…,pm,凸壳的边为e1,e2,…,em。并将凸壳顶点按顺序连接成边的ei加入T(三角剖分的边集合),并且ei的权值被赋为1。凸壳内点的集合为S1={pm+1,pm+2,…,pn}。
第二步:从内部点S1中任取一点pi,求与pi距离最近的点pj,将线段 存入T。
第三步:求与pj距离最近的点(除点pi外),设为pk,并将线段 加入T,并将这些边的权值设为1,而wij、wjk和wki的值加1,即为2。边的权值为2则表示该边为两个三角形共有。
第五步:对权值为1的边(除e1,e2,…,em外)的两个端点分别求与其距离最近的点,并将其连线(得到新的三角形)加入T,新三角形边的权值加1。
第六步:对权值为1的边重复上一步,当一条边被使用一次其权值增加1,直到所有边的权值均为2为止(除e1,e2,…,em外)。
贪心算法2中,第一步耗费O(nlgn);第二步需要计算n-1次距离与n-2次比较;第三步求pk要计算n-2次的距离与n-3次比较;第四步要进行(n-3)×3次的距离计算及(n-4)×3次比较;第五步至多进行n-6次的距离计算与n-7次比较;第六步到第五步的循环次数不超过3n-9;因此整个贪心算法2的时间复杂性为
O(nlgn)+O(n)+O(n)+O(n)+(n-6)×(3n-9)=O(n2)
㈢ 绁炵粡缃戠粶铡熺悊鍙婂簲鐢
绁炵粡缃戠粶铡熺悊鍙婂簲鐢
1. 浠涔堟槸绁炵粡缃戠粶锛
绁炵粡缃戠粶鏄涓绉嶆ā𨰾熷姩鐗╃炵粡缃戠粶琛屼负鐗瑰緛锛岃繘琛屽垎甯冨纺骞惰屼俊鎭澶勭悊镄勭畻娉曘傝繖绉岖绣缁滀緷闱犵郴缁熺殑澶嶆潅绋嫔害锛岄氲繃璋冩暣鍐呴儴澶ч噺鑺傜偣涔嬮棿鐩镐簰杩炴帴镄勫叧绯伙纴浠庤岃揪鍒板勭悊淇℃伅镄勭洰镄勚
浜虹被镄勭炵粡缃戠粶
2. 绁炵粡缃戠粶锘虹鐭ヨ瘑
鏋勬垚锛氩ぇ閲忕亩鍗旷殑锘虹鍏冧欢钬斺旂炵粡鍏幂浉浜掕繛鎺
宸ヤ綔铡熺悊锛氭ā𨰾熺敓鐗╃殑绁炵粡澶勭悊淇℃伅镄勬柟寮
锷熻兘锛氲繘琛屼俊鎭镄勫苟琛屽勭悊鍜岄潪绾挎ц浆鍖
鐗圭偣锛氭瘆杈冭交𨱒惧湴瀹炵幇闱炵嚎镐ф椠灏勮繃绋嬶纴鍏锋湁澶ц勬ā镄勮$畻鑳藉姏
绁炵粡缃戠粶镄勬湰璐锛
绁炵粡缃戠粶镄勬湰璐ㄥ氨鏄鍒╃敤璁$畻链鸿瑷妯℃嫙浜虹被澶ц剳锅氩喅瀹氱殑杩囩▼銆
3. 鐢熺墿绁炵粡鍏缁撴瀯
4. 绁炵粡鍏幂粨鏋勬ā鍨
xj涓鸿緭鍏ヤ俊鍙凤纴胃i涓洪槇鍊硷纴wij琛ㄧず涓庣炵粡鍏冭繛鎺ョ殑𨱒冨硷纴yi琛ㄧず杈揿嚭鍊
鍒ゆ柇xjwij鏄钖﹀ぇ浜庨槇鍊嘉竔
5. 浠涔堟槸阒埚硷纻
涓寸晫鍊笺
绁炵粡缃戠粶鏄妯′豢澶ц剳镄勭炵粡鍏冿纴褰揿栫晫鍒烘縺杈惧埌涓瀹氱殑阒埚兼椂锛岀炵粡鍏冩墠浼氩弹鍒烘縺锛屽奖鍝崭笅涓涓绁炵粡鍏冦
6. 鍑犵崭唬琛ㄦх殑缃戠粶妯″瀷
鍗曞眰鍓嶅悜绁炵粡缃戠粶钬斺旂嚎镐х绣缁
阒惰穬缃戠粶
澶氩眰鍓嶅悜绁炵粡缃戠粶锛埚弽鎺ㄥ︿範瑙勫垯鍗BP绁炵粡缃戠粶锛
Elman缃戠粶銆丠opfield缃戠粶銆佸弻钖戣仈𨱍宠板繂缃戠粶銆佽嚜缁勭粐绔炰簤缃戠粶绛夌瓑
7. 绁炵粡缃戠粶鑳藉共浠涔堬纻
杩愮敤杩欎簺缃戠粶妯″瀷鍙瀹炵幇鍑芥暟阃艰繎銆佹暟鎹镵氱被銆佹ā寮忓垎绫汇佷紭鍖栬$畻绛夊姛鑳姐傚洜姝わ纴绁炵粡缃戠粶骞挎硾搴旂敤浜庝汉宸ユ櫤鑳姐镊锷ㄦ带鍒銆佹満鍣ㄤ汉銆佺粺璁″︾瓑棰嗗烟镄勪俊鎭澶勭悊涓銆傝槠铹剁炵粡缃戠粶镄勫簲鐢ㄥ緢骞匡纴浣嗘槸鍦ㄥ叿浣撶殑浣跨敤杩囩▼涓鍒板簳搴斿綋阃夋嫨鍝绉岖绣缁灭粨鏋勬瘆杈冨悎阃傛槸鍊煎缑钥冭槛镄勚傝繖灏遍渶瑕佹垜浠瀵瑰悇绉岖炵粡缃戠粶缁撴瀯链変竴涓杈冨叏闱㈢殑璁よ瘑銆
8. 绁炵粡缃戠粶搴旂敤