Dijkstra是求最短路径,从未选过点中找最短的一条路,然后更新其他点到起点的距离。例如选择的最短点为k,则dj[k]表示起点到k之间的距离,此时更新其他点到起点的距离,dj[j] = min(dj[j],dj[k]+dj[k][j]);dj[j]比较原来的长度与经过k掉再到j点的长度,取最小。
模板如下:
void Dijkstra() { memset(vis,0,sizeof(vis)); for(int i=0;i<=n;++i) dj[i] = Map[0][i]; vis[0] = 1; for(int i=1;i<=n;++i) { int mindj = INF; int pos; for(int j=1;j<=n;++j) { if(dj[j]<mindj&&!vis[j]) { mindj = dj[j]; pos = j; } } vis[pos] = 1; for(int j=1;j<=n;++j) { if(!vis[j] && dj[j] > dj[pos] + Map[pos][j]) dj[j] = dj[pos] + Map[pos][j]; } } }
由于多个起点,只要设置多个起点到0起点的距离为0即可。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define INF (1<<30) #define N (1000+100) int Map[N][N]; int n; int dj[N],vis[N]; void Dijkstra() { memset(vis,0,sizeof(vis)); for(int i=0;i<=n;++i) dj[i] = Map[0][i]; vis[0] = 1; for(int i=1;i<=n;++i) { int mindj = INF; int pos; for(int j=1;j<=n;++j) { if(dj[j]<mindj&&!vis[j]) { mindj = dj[j]; pos = j; } } vis[pos] = 1; for(int j=1;j<=n;++j) { if(!vis[j] && dj[j] > dj[pos] + Map[pos][j]) dj[j] = dj[pos] + Map[pos][j]; } } } int main() { int t,s,d; while(~scanf("%d%d%d",&t,&s,&d)) { n = 0; for(int i=0;i<N;++i) for(int j=0;j<N;++j) { if(i != j) Map[i][j] = INF; else Map[i][j] = 0; } for(int i=0;i<t;++i) { int a,b,time; scanf("%d%d%d",&a,&b,&time); Map[a][b] = Map[b][a] = min(Map[a][b],time); n = max(max(a,b),n); } int src[N],dst[N]; for(int i=0;i<s;++i) { scanf("%d",&src[i]); Map[0][src[i]] = 0; } for(int i=0;i<d;++i) scanf("%d",&dst[i]); Dijkstra(); int res = INF; for(int i=0;i<d;++i) res = min(res,dj[dst[i]]); printf("%d\n",res); } return 0; }
跟2066一样,每次两点之间会有多条路,需要取最小的那条算,无语。。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define INF (1<<30) #define N (200+10) int Map[N][N]; int n; int dj[N],vis[N]; void Dijkstra() { memset(vis,0,sizeof(vis)); for(int i=0;i<=n;++i) dj[i] = Map[0][i]; vis[0] = 1; for(int i=1;i<=n;++i) { int pos,mindj = INF; for(int j=1;j<=n;++j) if(!vis[j]&&dj[j]<mindj) { mindj = dj[j]; pos = j; } vis[pos] = 1; for(int j=1;j<=n;++j) if(!vis[j]) dj[j] = min(dj[j],dj[pos]+Map[pos][j]); } } int main() { int m; while(~scanf("%d%d",&n,&m)) { for(int i=0;i<=n;++i) for(int j=0;j<=n;++j) { if(i != j) Map[i][j] = INF; else Map[i][j] = 0; } for(int i=0;i<m;++i) { int a,b,x; scanf("%d%d%d",&a,&b,&x); Map[a+1][b+1] = Map[b+1][a+1] = min(Map[a+1][b+1],x); } int s,t; scanf("%d%d",&s,&t); ++s,++t; Map[0][s] = 0; Dijkstra(); if(dj[t] >= INF) printf("-1\n"); else printf("%d\n",dj[t]); } return 0; }
二维最短路径,求最短路径,如果最短路径有多条,求费用最少。原理一样,不难
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define INF (1<<30) #define N (1000+10) int n,m; int Map[N][N],Price[N][N]; int dj[N],cost[N],vis[N]; void Dijkstra() { memset(vis,0,sizeof(vis)); vis[0] = 1; for(int i=0;i<=n;++i) { dj[i] = Map[0][i]; cost[i] = Price[0][i]; } for(int i=1;i<=n;++i) { int mindj=INF,pos; for(int j=1;j<=n;++j) if(!vis[j]&&dj[j]<mindj) { mindj = dj[j]; pos = j; } vis[pos] = 1; for(int j=1;j<=n;++j) if(!vis[j]&&(dj[j] > dj[pos] + Map[pos][j]|| (dj[j]==dj[pos] + Map[pos][j] && cost[j] > cost[pos] + Price[pos][j]))) { dj[j] = dj[pos] + Map[pos][j]; cost[j] = cost[pos] + Price[pos][j]; } } } int main() { while(~scanf("%d%d",&n,&m),n&&m) { for(int i=0;i<=n;++i) for(int j=0;j<=n;++j) { if(i != j) Map[i][j] = INF; else Map[i][j] = 0; } memset(Price,0,sizeof(Price)); for(int i=0;i<m;++i) { int a,b,d,p; scanf("%d%d%d%d",&a,&b,&d,&p); if(d < Map[a][b] || (d==Map[a][b]&&p < Price[a][b])) { Map[a][b] = Map[b][a] = d; Price[a][b] = Price[b][a] = p; } } int s,t; scanf("%d%d",&s,&t); Map[0][s] = 0; Dijkstra(); printf("%d %d\n",dj[t],cost[t]); } return 0; }
用map把地名换成数字。
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<string.h> #include<algorithm> using namespace std; #define INF (1<<30) #define N (160) map<string,int> msi; int Map[N][N]; int cnt; int vis[N],dj[N]; void Dijkstra() { memset(vis,0,sizeof(vis)); vis[0] = 1; for(int i=0;i<=cnt;++i) dj[i] = Map[0][i]; for(int i=1;i<=cnt;++i) { int pos,mindj = INF; for(int j=1;j<=cnt;++j) if(!vis[j] && dj[j] < mindj) { pos = j; mindj = dj[j]; } vis[pos] = 1; for(int j=1;j<=cnt;++j) if(!vis[j]) dj[j] = min(dj[j],dj[pos]+Map[pos][j]); } } int main() { int n; while(~scanf("%d",&n),n!=-1) { for(int i=0;i<N;++i) for(int j=0;j<N;++j) { if(i!=j) Map[i][j] = INF; else Map[i][j] = 0; } msi.clear(); char a[40],b[40]; int ia,ib,t,dst; scanf("%s%s",a,b); cnt = 0; msi[a] = ++cnt; dst = (strcmp(a,b)==0?cnt:++cnt); msi[b] = dst; Map[0][1] = 0; for(int i=0;i<n;++i) { scanf("%s%s%d",a,b,&t); pair<map<string,int>::iterator,bool>pmb = msi.insert(pair<string,int>(a,0)); if(pmb.second) msi[a] = ++cnt; pmb = msi.insert(pair<string,int>(b,0)); if(pmb.second) msi[b] = ++cnt; //换成下面部分也可以 /*(if(!msi[a]) msi[a] = ++cnt; if(!msi[b]) msi[b] = ++cnt; */ ia = msi[a]; ib = msi[b]; if(t < Map[ia][ib]) Map[ia][ib] = Map[ib][ia] = t; } Dijkstra(); if(dj[dst] >= INF) printf("-1\n"); else printf("%d\n",dj[dst]); } return 0; }