一.dijkstra算法模板:
//dijkstra
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f
#define max 1000+10
using namespace std;
int visit[max],map[max][max],dist[max],time[max];
int n,m;
int start;
void dijkstra(int start)
{
int i,j,next;
int mindist;
for(i=1;i<=n;i++)
{
visit[i]=0;
dist[i]=map[start][i];
}
visit[start]=1;
for(i=2;i<=n;i++)
{
next=i;
mindist=INF;
for(j=1;j<=n;j++)
{
if(!visit[j]&&mindist>dist[j])
{
mindist=dist[j];
next=j;
}
}
visit[next]=1;
for(j=1;j<=n;j++)
{
if(!visit[j]&&dist[next]+map[next][j]<dist[j])
dist[j]=dist[next]+map[next][j];
}
}
}
int main()
{
int i,j,x,y,c,road,end;
while(scanf("%d%d%d",&n,&m,&start)!=EOF)
{
memset(time,INF,sizeof(time));
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(i==j)
map[i][j]=0;
else
map[i][j]=INF;
}
}
while(m--)
{
scanf("%d%d%d",&x,&y,&c);
if(map[y][x]>c)
map[y][x]=c;
}
dijkstra(start);
scanf("%d",&road);
for(i=0;i<road;i++)
{
scanf("%d",&end);
time[i]=dist[end];
}
sort(time,time+road);
if(time[0]==INF)
printf("-1\n");
else
printf("%d\n",time[0]);
}
return 0;
}
二.题目模板
1.城市平乱
题目:已知有一个城市发生叛乱,有N个部队维护M个城市的治安。知道城市之间相互到达的时间,N个部队分布在任意N个城市,问一个城市暴乱后,最少需要多长时间有部队营救。
思路:运用dijkstra算法,把暴乱地点当做起点,求出到达每个位置的最短时间,然后再比较一下,所有最短的来。
代码:https://blog.csdn.net/chenzhenyu123456/article/details/43973471
2.find the safest road
题目:已知一个矩阵表示城市建的安全系数,一条从u 到 v 的通道P 的安全度为Safe(P) = s(e1)*s(e2)…*s(ek) e1,e2,ek是P 上的边,输出两个城市间最安全道路的安全系数。
思路:dijkstra算法的模板题,但是要注意 dist[j]=dist[next]*map[next][j]; ,然后全程double
代码:https://blog.csdn.net/chenzhenyu123456/article/details/44118045
3.最短路径+最小花费问题
题目:给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
思路:直接在dijkstra算法里改一下模板,当dist[next]+map[next][j]==dist[j]&&money[next]+cost[next][j]<money[j] 时,进行money[j]=money[next]+cost[next][j]; 操作。然后~
代码:https://blog.csdn.net/chenzhenyu123456/article/details/44247177
4.对于数据太大的,map无法存储,可以用链表形式
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1);
const int MAXN = 200009;
int n, m, tot, head[MAXN];
bool vis[MAXN];
ll f[MAXN];
struct Edge
{
int to, w, nex;
}edge[MAXN * 2];
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
}
void addedge(int x, int y, int z)
{
edge[tot] = {y, z, head[x]};
head[x] = tot++;
}
void solve()
{
memset(vis, 0, sizeof(vis));
memset(f, LL_INF, sizeof(f));
f[1] = 0;
queue <int> q;
q.push(1);
vis[1] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
vis[u] = 0;
for (int i = head[u]; i != -1; i = edge[i].nex)
{
int v = edge[i].to;
if (f[u] + edge[i].w < f[v]) {
f[v] = f[u] + edge[i].w;
if (!vis[v]) {
q.push(v);
vis[v] = 1;
}
}
}
}
}
int main()
{
while (~scanf("%d %d", &n, &m)) {
init();
for (int i = 1; i <= m; ++i) {
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
addedge(x, y, z);
addedge(y, x, z);
}
solve();
if (f[n] == LL_INF) puts("qwb baka");
else printf("%lld\n", f[n]);
}
return 0;
}
5.最少换乘
题目大意:给定M条单向路径(由左到右按顺序给出),问最少换乘多少站使得能从1-n,不能的话输出-1
思路:将给定的单向边(所有)的权值赋为1(注意是任意两个距离为1),然后用dijkstra算法跑一遍再减一(多算了第一个线程,不计入总和)
坑点:输入的数据要按string类型进行处理。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 500+10
#define INF 0x3f3f3f
using namespace std;
char str[1200];
int m, n;
int map[MAX][MAX];
int dist[MAX];
int vis[MAX];
void init()//初始化
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n ;j++)
{
if(i == j)
map[i][j] = 0;
else
map[i][j] = INF;
}
}
}
void getmap()//建图
{
int rec[MAX];
int sum;
int t;
int i, j, k;
for(i = 0; i < m; i++)
{
gets(str);
t = 0;
for(j = 0; j < strlen(str); j++)
{
if(str[j] != ' ')
{
sum = 0;
while(str[j] != ' ' && j < strlen(str))
{
sum = sum * 10 + (str[j]-'0');
++j;
}
rec[t++] = sum;
}
}
for(j = 0; j < t; j++)//每次更新
{
for(k = j+1; k < t; k++)
{
map[rec[j]][rec[k]] = 1;
}
}
}
}
void dijkstra()
{
int i, j;
int min, next;
for(i = 1; i <= n; i++)
{
dist[i] = map[1][i];
vis[i] = 0;
}
vis[1] = 1;
for(i = 2; i <= n; i++)
{
min = INF;
for(j = 1; j <= n; j++)
{
if(!vis[j] && min > dist[j])
{
next = j;
min = dist[j];
}
}
vis[next] = 1;
for(j = 1; j <= n; j++)
{
if(!vis[j] && map[next][j] + dist[next] < dist[j])
{
dist[j] = dist[next] + map[next][j];
}
}
}
if(dist[n] == INF)
printf("NO\n");
else
printf("%d\n", dist[n]-1);
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &m, &n);
getchar();
init();//初始化
getmap();//建图
dijkstra();//求最短路
}
return 0;
}
6.frogger—两点最大距离的最小值
题目大意:给定n个点的坐标,求第1个和第二个点的所有路径中两点间的最大值
思路:利用floyd,d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));就是找其中最大值的最小值保存起来。
具体见代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=205;
double d[N][N];
int x[N],y[N],n;
void floyd()
{
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));
}
int main()
{
int cas=0;
while(scanf("%d",&n),n)
{
memset(d,0x3f,sizeof(d));
for(int i=1;i<=n;++i)
{
scanf("%d%d",&x[i],&y[i]);
for(int j=1;j<i;++j)
{
int tx=x[i]-x[j],ty=y[i]-y[j];
d[i][j]=d[j][i]=sqrt(tx*tx+ty*ty);
}
}
floyd();
printf("Scenario #%d\nFrog Distance = %.3f\n\n",++cas,d[1][2]);
}
return 0;
}
7.find the mincost route(考察对floyd算法的理解)
题目大意:杭州有N个景区,景区之间有一些双向的路来连接,现在8600想找一条旅游路线,这个路线从A点出发并且最后回到A点,假设经过的路线为V1,V2,....VK,V1,那么必须满足K>2,就是说至除了出发点以外至少要经过2个其他不同的景区,而且不能重复经过同一个景区。现在8600需要你帮他找一条这样的路线,并且花费越少越好。
思路:考虑到floyd算法在循环中,穷举每个点k作为中间节点来更新其他点a,b之间的距离,而当某个点k未被枚举到时,是不会有一条路径包含在中间的,他顶多可以作为路径的起点或者终点。利用这点,在未枚举到的k作为某中间点时,可以枚举一下与k相连的两条边,即i->k->j