A. 怎樣用DIJKSTRA演算法設計最短路徑
以下................
輸入時,將s,t,x,y,z五個點按照1,2,3,4,5起別名,輸入格式按照下圖例所示
當提示Please enter the vertex where Dijkstra algorithm starts:時輸入演算法的起始點
比如計算結果v1v4v2表示從點1到點2經過1,4,2為最短路徑
Dijkstra演算法的完整實現版本,演算法的源代碼
/* Dijkstra.c
Copyright (c) 2002, 2006 by ctu_85
All Rights Reserved.
*/
#include "stdio.h"
#include "malloc.h"
#define maxium 32767
#define maxver 9 /*defines the max number of vertexs which the programm can handle*/
#define OK 1
struct Point
{
char vertex[3];
struct Link *work;
struct Point *next;
};
struct Link
{
char vertex[3];
int value;
struct Link *next;
};
struct Table /*the workbannch of the algorithm*/
{
int cost;
int Known;
char vertex[3];
char path[3];
struct Table *next;
};
int Dijkstra(struct Point *,struct Table *);
int PrintTable(int,struct Table *);
int PrintPath(int,struct Table *,struct Table *);
struct Table * CreateTable(int,int);
struct Point * FindSmallest(struct Table *,struct Point *);/*Find the vertex which has the smallest value reside in the table*/
int main()
{
int i,j,num,temp,val;
char c;
struct Point *poinpre,*poinhead,*poin;
struct Link *linpre,*linhead,*lin;
struct Table *tabhead;
poinpre=poinhead=poin=(struct Point *)malloc(sizeof(struct Point));
poin->next=NULL;
poin->work=NULL;
restart:
printf("Notice:if you wanna to input a vertex,you must use the format of number!\n");
printf("Please input the number of points:\n");
scanf("%d",&num);
if(num>maxver||num<1||num%1!=0)
{
printf("\nNumber of points exception!");
goto restart;
}
for(i=0;i<num;i++)
{
printf("Please input the points next to point %d,end with 0:\n",i+1);
poin=(struct Point *)malloc(sizeof(struct Point));
poinpre->next=poin;
poin->vertex[0]='v';
poin->vertex[1]='0'+i+1;
poin->vertex[2]='\0';
linpre=lin=poin->work;
linpre->next=NULL;
for(j=0;j<num-1;j++)
{
printf("The number of the %d th vertex linked to vertex %d:",j+1,i+1);
scanf("%d",&temp);
if(temp==0)
{
lin->next=NULL;
break;
}
else
{
lin=(struct Link *)malloc(sizeof(struct Link));
linpre->next=lin;
lin->vertex[0]='v';
lin->vertex[1]='0'+temp;
lin->vertex[2]='\0';
printf("Please input the value betwixt %d th point towards %d th point:",i+1,temp);
scanf("%d",&val);
lin->value=val;
linpre=linpre->next;
lin->next=NULL;
}
}
poinpre=poinpre->next;
poin->next=NULL;
}
printf("Please enter the vertex where Dijkstra algorithm starts:\n");
scanf("%d",&temp);
tabhead=CreateTable(temp,num);
Dijkstra(poinhead,tabhead);
PrintTable(temp,tabhead);
return OK;
}
struct Table * CreateTable(int vertex,int total)
{
struct Table *head,*pre,*p;
int i;
head=pre=p=(struct Table *)malloc(sizeof(struct Table));
p->next=NULL;
for(i=0;i<total;i++)
{
p=(struct Table *)malloc(sizeof(struct Table));
pre->next=p;
if(i+1==vertex)
{
p->vertex[0]='v';
p->vertex[1]='0'+i+1;
p->vertex[2]='\0';
p->cost=0;
p->Known=0;
}
else
{
p->vertex[0]='v';
p->vertex[1]='0'+i+1;
p->vertex[2]='\0';
p->cost=maxium;
p->Known=0;
}
p->next=NULL;
pre=pre->next;
}
return head;
}
int Dijkstra(struct Point *p1,struct Table *p2) /* Core of the programm*/
{
int costs;
char temp;
struct Point *poinhead=p1,*now;
struct Link *linna;
struct Table *tabhead=p2,*searc,*result;
while(1)
{
now=FindSmallest(tabhead,poinhead);
if(now==NULL)
break;
result=p2;
result=result->next;
while(result!=NULL)
{
if(result->vertex[1]==now->vertex[1])
break;
else
result=result->next;
}
linna=now->work->next;
while(linna!=NULL) /* update all the vertexs linked to the signed vertex*/
{
temp=linna->vertex[1];
searc=tabhead->next;
while(searc!=NULL)
{
if(searc->vertex[1]==temp)/*find the vertex linked to the signed vertex in the table and update*/
{
if((result->cost+linna->value)<searc->cost)
{
searc->cost=result->cost+linna->value;/*set the new value*/
searc->path[0]='v';
searc->path[1]=now->vertex[1];
searc->path[2]='\0';
}
break;
}
else
searc=searc->next;
}
linna=linna->next;
}
}
return 1;
}
struct Point * FindSmallest(struct Table *head,struct Point *poinhead)
{
struct Point *result;
struct Table *temp;
int min=maxium,status=0;
head=head->next;
poinhead=poinhead->next;
while(head!=NULL)
{
if(!head->Known&&head->cost<min)
{
min=head->cost;
result=poinhead;
temp=head;
status=1;
}
head=head->next;
poinhead=poinhead->next;
}
if(status)
{
temp->Known=1;
return result;
}
else
return NULL;
}
int PrintTable(int start,struct Table *head)
{
struct Table *begin=head;
head=head->next;
while(head!=NULL)
{
if((head->vertex[1]-'0')!=start)
PrintPath(start,head,begin);
head=head->next;
}
return OK;
}
int PrintPath(int start,struct Table *head,struct Table *begin)
{
struct Table *temp=begin->next,*p,*t;
p=head;
t=begin;
if((p->vertex[1]-'0')!=start&&p!=NULL)
{
while(temp->vertex[1]!=p->path[1]&&temp!=NULL)
temp=temp->next;
PrintPath(start,temp,t);
printf("%s",p->vertex);
}
else
if(p!=NULL)
printf("\n%s",p->vertex);
return OK;
}
B. 10個常用演算法
原理:
二分法查找,也稱為折半法,是一種在有序數組中查找特定元素的搜索演算法。
一般步驟:
(1)確定該區間的中間位置K;
(2)將查找的值T與array[k]比較。
若相等,查找成功返回此位置;否則確定新的查找區域,繼續二分查找。每一次查找與中間值比較,可以確定是否查找成功,不成功當前查找區間將縮小一半,遞歸查找即可。
原理:
一種通過重復將問題分解為同類的子問題而解決問題的方法
典型例子:
斐波那契數列
描述: 斐波那契數列 指的是這樣一個數列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368.....自然中的斐波那契數列") 自然中的斐波那契數列,這個數列從第3項開始,每一項都等於前兩項之和。
解決方式:
原理:
在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就「回溯」返回,嘗試別的路徑。
回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。
但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為「回溯點」。
解決問題一般步驟:
1、 針對所給問題,定義問題的解空間,它至少包含問題的一個(最優)解。
2 、確定易於搜索的解空間結構,使得能用回溯法方便地搜索整個解空間 。
3 、以深度優先的方式搜索解空間,並且在搜索過程中用剪枝函數避免無效搜索。
典型例子:
八皇後問題
描述:在8×8格的國際象棋上擺放八個皇後,使其不能互相攻擊,即任意兩個皇後都不能處於同一行、同一列或同一斜線上,問有多少種擺法。
解決方式: https://blog.csdn.net/weixin_41865447/article/details/80034433
概念:
將雜亂無章的數據元素,通過一定的方法按關鍵字順序排列的過程叫做排序。
分類:
非穩定排序演算法:快速排序、希爾排序、堆排序、直接選擇排序
穩定的排序演算法:基數排序、冒泡排序、直接插入排序、折半插入排序、歸並排序
十個常用排序演算法
利用計算機的高性能來有目的的窮舉一個問題解空間的部分或所有的可能情況,從而求出問題的解的一種方法。
分類:
枚舉演算法、深度優先搜索、廣度優先搜索、A*演算法、回溯演算法、蒙特卡洛樹搜索、散列函數等演算法。
將一個數據轉換為一個標志,這個標志和源數據的每一個位元組都有十分緊密的關系。
很難找到逆向規律
只要符合散列思想的演算法都可以被稱為是Hash演算法
對不同的關鍵字可能得到同一散列地址,即key1≠key2,而f(key1)=f(key2),這種現象稱為 碰撞 。
原理
在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的是在 某種意義上的局部最優解 。
從問題的某一個初始解出發一步一步地進行,根據某個優化測度,每一步都要確保能獲得局部最優解。每一步只考慮一個數據,他的選取應該滿足局部優化的條件。若下一個數據和部分最優解連在一起不再是可行解時,就不把該數據添加到部分解中,直到把所有數據枚舉完,或者不能再添加演算法停止。
一種近似演算法
一般步驟:
1、建立數學模型來描述問題;
2、把求解的問題分成若干個子問題;
3、對每一子問題求解,得到子問題的局部最優解;
4、把子問題的解局部最優解合成原來解問題的一個解。
典型例子:
0/1背包問題
馬踏棋盤
均分紙牌
例題: https://www.cnblogs.com/hust-chen/p/8646009.html
概念:
分治演算法的基本思想是將一個規模為N的問題分解為K個規模較小的子問題,這些子問題相互獨立且與原問題性質相同。求出子問題的解,就可得到原問題的解。即一種分目標完成程序演算法,簡單問題可用二分法完成。
一般步驟:
(1)分解,將要解決的問題劃分成若干規模較小的同類問題;
(2)求解,當子問題劃分得足夠小時,用較簡單的方法解決;
(3)合並,按原問題的要求,將子問題的解逐層合並構成原問題的解。
典型例子:
排序中:歸並排序、堆排序、快速排序;
實例:找偽幣、求最值、棋盤覆蓋
https://ke..com/item/%E5%88%86%E6%B2%BB%E7%AE%97%E6%B3%95/3263297
概念:
用於求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。每一個解都對應於一個值,我們希望找到具有最優值的解。
動態規劃一般可分為線性動規,區域動規,樹形動規,背包動規四類。
舉例:
線性動規:攔截導彈,合唱隊形,挖地雷,建學校,劍客決斗等;
區域動規:石子合並, 加分二叉樹,統計單詞個數,炮兵布陣等;
樹形動規:貪吃的九頭龍,二分查找樹,聚會的歡樂,數字三角形等;
背包問題:01背包問題,完全背包問題,分組背包問題,二維背包,裝箱問題,擠牛奶(同濟)等;
應用實例:
最短路徑問題 ,項目管理,網路流優化等;
https://ke..com/item/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/529408?fromtitle=%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%AE%97%E6%B3%95&fromid=15742703&fr=aladdin
概念:
在一個給定的字元文本內搜尋出自己想要找的一個字元串,平常所用的各種文本編輯器里的ctrl+F大多就是使用的這些字元匹配演算法。
分類:
KMP、BM、Sunday、Horspool、RK
參考:
https://cloud.tencent.com/developer/news/282694
https://blog.csdn.net/paincupid/article/details/81159320