寫在前面:圖論題的調試真感人
讓咱們進入正題node
emmm 顧名思義最短路就是求一個點到另一個點的最小距離
通常來講最短路分爲:單源最短路和多源最短路
單源最短路就是求一個源點到另外多個點的最短距離
而多源最短路就是求多個點到其餘點的最短距離
算法通常有:算法
for(int k=1;k<=n;++k)//枚舉中轉點 for(int i=1;i<=n;++i)//枚舉邊的起點 for(int j=1;j<=n;++j)//枚舉邊的終點 if(a[i][j]>a[i][k]+a[k][j])//鬆弛操做(即利用第三個點來判斷是否能夠更新目標兩個點的最短距離) a[i][j]=a[i][k]+a[k][j];//a[i][j]是從i到j的最小值
關於k爲何要枚舉在第一層循環:
剛纔已經說過floyd相似於dp,而k就是dp的階段(dp的階段顯然要枚舉在第一層的),其實a原本是三維a[k][i][j]表示只通過前k個點從i到j的最短路,而能夠將第一維的k捨去(like揹包) 因此就成了如今的樣子啦函數
void dij(int s){ memset(vis,0,sizeof(vis)); vis[s] = 1;//將s放入S集合 for(int i = 1;i <= n;++i){ if(g[s][i]){dis[i] = g[s][i];}//若是從s到i有路的話 就將s到i的距離設置爲長度 else dis[i] = 0x3f3f3f3f;//將其餘點設置爲正無窮(即目前沒法到達) } dis[s] = 0;//源點s到本身的最短距離是0 for(int i = 1;i < n;++i){//遍歷每個點以求出每個點距離源點的最小距離 int Min = 0x3f3f3f3f,k = 0;//Min維護這一輪維護後要放入S集合的距離最小值,k維護要放入S集合的點 for(int j = 1;j <= n;++j) if(!vis[j] && Min > dis[j]){//若是點j尚未在S集合中而且s到當前節點的距離更小 Min = dis[j];k = j; } vis[k] = 1;//k放入S集合 for(int j = 1;j <= n;++j){ if(g[k][j] && dis[j] > dis[k] + g[k][j]){//若是能夠經過k鬆弛 dis[j] = dis[k] + g[k][j];//更新到j的最小值 } } } }
關於優化:優化
void dij(int x){ priority_queue<node> q; memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); dis[x] = 0; q.push(node(x,0)); while(!q.empty()){ node t = q.top();q.pop(); int k = t.num; if(vis[k])continue; vis[k] = 1; for(int i = head[k];i;i = a[i].next){ int v = a[i].to; if(dis[v] > dis[k] + a[i].dis){ dis[v] = dis[k] + a[i].dis;q.push(node(v,dis[k] + a[i].dis)); } } } }
for(int i = 0;i < n;++i)//枚舉頂點 for each(i,j)//對於每一條邊 song_chi(i,j)//鬆弛操做
void BF(int u){ memset(d,0x3f,sizeof(d)); d[u] = 0; for(int i = 1;i < n;++i){ for(int j = 1;j <= cnt;++j){//cnt存的是圖中共有幾個邊 int x = a[j].from,y = a[j].to,z = a[j].dis; d[y] = min(d[y],d[x] + z);//鬆弛操做 } } }
bool check(){ for(int i = 1;i <= cnt;++i){ int x = a[i].from,y = a[i].to,z = a[i].dis; if(d[y] < d[x] + z)return 1; } return 0; } //主函數中: if(check()){ printf("NO\n");return 0; }
struct node{ int to,dis,next; }a[maxn]; void add(int x,int y,int z){ a[++cnt].to = y;a[cnt].next = head[x];a[cnt].dis = z;head[x] = cnt; } bool spfa(int s){ memset(dis,0x3f,sizeof(dis));dis[s] = 0;//dis存到源點的最短距離 queue<int>q; q.push(s);flag[s] = 1;//s入隊 while(!q.empty()){ int u = q.front();q.pop();flag[u] = 0;//由於一個節點u可能屢次進隊 for(int i = head[u];i;i = a[i].next){//鄰接表存邊 int v = a[i].to; if(dis[v] > dis[u] + a[i].dis){//鬆弛操做:沒錯,仍是我!!! dis[v] = dis[u] + a[i].dis; if(!flag[v]){//優化 if(++num[v] >= n)return 0;若是同一個點被屢次鬆弛 那麼確定有負環(這個判斷也比剛纔的少女口阿 把前輩666扣在公屏上) q.push(v);flag[v] = 1;//v進隊,標記 } } } } return 1; } //主函數中: if(!spfa(源點))輸出NO else 輸出距離
好了 本文閱讀到此結束了spa
碼字不易 推薦走起調試
若是您有不懂的地方 或者 您發現代碼有問題能夠在下方評論或者給博主留言code
感謝觀看>_<對象