圖,根據點數和邊數可分爲三種:徹底圖,稠密圖與稀疏圖。優化
徹底圖,即\(m=n^2\)的圖\((m\)爲邊數,\(n\)爲點數\()\)。如:spa
1 1 0 1 2 1 1 3 2 2 1 1 2 2 0 2 3 3 3 1 2 3 2 3 3 3 0
這個數據是一個徹底圖。code
稠密圖,即\(m\)十分接近於\(n^2\)的圖。如:blog
1 1 0 1 2 1 1 3 2 2 1 1 2 2 0 2 3 3 3 1 2
這個數據是一個稠密圖。ci
稀疏圖,即\(m\)遠遠低於\(n^2\)的圖。如:it
1 2 1 1 3 5 2 3 7 2 4 3 3 4 5
這個數據是一個稀疏圖。io
根據方向可分爲兩種:有向圖和無向圖。table
有向圖,就是邊有方向,好比說,\(1\)~\(2\)有一條邊,而\(2\)~\(1\)沒有邊,則只能從\(1\)前往\(2\),不能從\(2\)前往\(1\),相似於現實中的單行道。class
無向圖,就是邊無方向,好比說,\(1\)~\(2\)有一條邊,而\(2\)~\(1\)沒有邊,則能夠從\(1\)前往\(2\),也能夠從\(2\)前往\(1\),相似於現實中的雙行道。nio
就相似於現實中路的長度。
圖大概長這樣:
適用於\(n \le 10000\)。
\(Code:\)
int dis[n][n]; int inf=99999999; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j)dis[i][j]=inf; cin>>u>>v>>w; dis[u][v]=w;
鄰接矩陣,就是用矩陣來存儲圖,\(dis[i][j]\)即表明\(i\)~\(j\)的最短路徑。如一個有向圖:
1 1 0 1 2 1 1 3 2 2 1 1 2 2 0 2 3 3 3 1 2
這個數據用鄰接表存儲是這樣的:
\(dis\) | \(1\) | \(2\) | \(3\) |
---|---|---|---|
\(1\) | 0 |
1 |
2 |
\(2\) | 1 |
0 |
3 |
\(3\) | 2 |
inf |
0 |
適用於全部狀況。
struct edge { int u,v,w; }e[m]; ... cin>>u>>v>>w; e[cnt]={(edge)u,v,w};
適用於全部狀況。
int u[m],v[m],w[m],next[2*m],first[m]; ... cin>>u[cnt]>>v[cnt]>>w[cnt]; next[cnt]=first[u[cnt]]; first[u[cnt]]=cnt;
時間複雜度:\(O((m+n)\) \(log\) \(n)\)
使用鄰接表。
void dijkstra(int i) { for(int j=0;j<=n;j++) dis[j]=inf; dis[i]=0; memset(book,false,sizeof(book)); priority_queue<pair<int,int>>q; q.push(make_pair(0,i)); while(q.size()) { int x=q.top().second; q.pop(); if(book[x])continue; book[x]=true; for(int k=first[x];k;k=next[k]) { if(dis[v[k]]>dis[u[k]]+w[k]) { dis[v[k]]=dis[u[k]]+w[k]; q.push(make_pair(-dis[v[k]],v[k])); } } } }
時間複雜度:\(O(\)玄\()\)。
使用鄰接表\(/\)邊表。
void spfa(int i) { for(int j=0;j<=n;j++) dis[j]=inf; dis[i]=0; memset(book,false,sizeof(book)); queue<int>q; q.push(i); book[i]=true; while(!q.empty()) { int k=first[q.front()]; while(k!=-1) { if(dis[v[k]]>dis[u[k]]+w[k]) { dis[v[k]]=dis[u[k]]+w[k]; if(book[v[k]]==false) { q.push(v[k]); book[v[k]]=true; } } k=next[k]; } book[q.front()]=false; q.pop(); } }
時間複雜度:\(O(n^3)\)
使用鄰接矩陣。
for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
圖的最小生成樹指,權值和最小的生成樹。
struct edge { int u,v,w; }e[3240010]; struct bcj { int father[1810]; void start(int n) {for(int i=0;i<=n;i++)father[i]=i;} int find(int x) {if(father[x]!=x)father[x]=find(father[x]);return father[x];} void unionn(int x,int y) {x=find(x);y=find(y);if(x!=y)father[y]=x;} bool judge(int x,int y) {if(find(x)==find(y))return true;return false;} }; bool cmp(edge a,edge b) { return a.w<b.w; } ... sort(e+1,e+1+m,cmp); uf.start(n); for(int i=1;i<=m;i++) { if(!uf.judge(e[i].u,e[i].v)) { cnt++; ans+=e[i].w; uf.unionn(e[i].u,e[i].v); } if(cnt==n-1)break; }