您的位置:首页 > 其它

最短路相关模板

2017-08-26 18:37 330 查看

spfa:

//适合稀疏图
const int N = 1010, INF = 0x3f3f3f3f; //N是点数
struct edge
{
int to, cost, next;
}g[N*N*2];
int cnt, head
;
int dis
;
bool vis
;
void init() //初始化
{
cnt = 0;
memset(head, -1, sizeof head);
}
void add_edge(int v, int u, int cost) //加单向边,双向边则调换v,u位置再加一次
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
void spfa(int s) //从s到其他点的最短路
{
queue<int> que;
memset(vis, 0, sizeof vis);
memset(dis, 0x3f, sizeof dis);
que.push(s), dis[s] = 0, vis[s] = true;
while(! que.empty())
{
int v = que.front(); que.pop();
vis[v] = false;
for(int i = head[v]; i != -1; i = g[i].next)
{
int u = g[i].to;
if(dis[u] > dis[v] + g[i].cost)
{
dis[u] = dis[v] + g[i].cost;
if(! vis[u]) que.push(u), vis[u] = true;
}
}
}
}


spfa判负环:

//用spfa判断有没有点入队超过n次,若有则存在负环,用等于n次判断是不对的,比如只有一个点
bool spfa(int s, int n)
{
queue<int> que;
memset(dis, 0x3f, sizeof dis);
memset(num, 0, sizeof num);
memset(vis, 0, sizeof vis);
que.push(s), dis[s] = 0, vis[s] = true, num[s]++;
while(! que.empty())
{
int v = que.front(); que.pop();
vis[v] = false;
for(int i = head[v]; i != -1; i = g[i].next)
{
int u = g[i].to;
if(dis[u] > dis[v] + g[i].cost)
{
dis[u] = dis[v] + g[i].cost;
if(! vis[u])
{
que.push(u), vis[u] = true, num[u]++;
if(num[u] > n) return true;//入队次数超过点数,存在负环
}
}
}
}
return false;
}


二叉堆优化djikstra:

//适合稠密图
typedef pair<int,int> pii;
const int N = 1010, INF = 0x3f3f3f3f; //N是点数
struct edge
{
int to, cost, next;
}g[N*N*2];
int cnt, head
;
int dis
;
void init() //初始化
{
cnt = 0;
memset(head, -1, sizeof head);
}
void add_edge(int v, int u, int cost) //加边
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
void dijkstra(int s) //从s到其他点的最短路
{
priority_queue<pii, vector<pii>, greater<pii> > que;
memset(dis, 0x3f, sizeof dis);
dis[s] = 0;
que.push(pii(dis[s], s));
while(! que.empty())
{
pii p = que.top(); que.pop();
int v = p.second;
if(dis[v] < p.first) continue;
for(int i = head[v]; i != -1; i = g[i].next)
{
int u = g[i].to;
if(dis[u] > dis[v] + g[i].cost)
{
dis[u] = dis[v] + g[i].cost;
que.push(pii(dis[u], u));
}
}
}
}


floyd:

//点下标1~n
const int N = 100 + 10, INF = 0x3f3f3f3f;
int dis[N][N]; //dis[v][u]初始为(v,u)的边权值,存在设为INF,但dis[i][i]=0
void floyd(int n)
{
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]);
}


floyd求无向图最小环:

关于记录路径:定义pro[i][j]为点i到点j路径上的倒数第二个点,倒数第一个自然是j,初始化pro[i][j]为i。当dis[i][j] > dis[i][k] + dis[k][j]成立时,意味着点i到点j的路径要改成点i到点k再到点j,而dis[k][j]已知,意味着pro[k][j]已知,即点k到点j的路径已知,所以此时应该把pro[k][j]存到pro[i][j]中,即pro[i][j] = pro[k][j]

//点下标1~n
const int N = 110, INF = 1<<28;
int tot;
int g

, dis

, pro

, path
;
int floyd(int n)
{
int res = INF;
for(int k = 1; k <= n; k++)
{
for(int i = 1; i < k; i++)
for(int j = i+1; j < k; j++)
{
int tmp = dis[i][j] + g[i][k] + g[k][j]; //这里INF要保证3*INF不溢出
if(res > tmp)
{
res = tmp;
tot = 0;
int p = j;
while(p != i)
{
path[tot++] = p;
p = pro[i][p];
}
path[tot++] = i, path[tot++] = k;
}
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(dis[i][j] > dis[i][k] + dis[k][j])
{
dis[i][j] = dis[i][k] + dis[k][j];
pro[i][j] = pro[k][j];
}
}
return res;
}
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(i == j) g[i][j] = dis[i][j] = 0;
else g[i][j] = dis[i][j] = INF;
pro[i][j] = i;
}
for(int i = 1; i <= m; i++)
{
int v, u, c;
scanf("%d%d%d", &v, &u, &c);
g[v][u] = g[u][v] = dis[v][u] = dis[u][v] = min(g[v][u], c);
}
int res = floyd(n);
if(res == INF) printf("No solution.\n");
else
{
for(int i = tot-1; i >= 0; i--) printf("%d%c", path[i], i == 0 ? '\n' : ' ');
}
}
return 0;
}


k短路:

//用dijkstra+Astar求第k短路,同一条边可以经过多次
//代码是有向图,有向图可能第k短路可能不存在,且要建正向图和反向图
//无向图第k短路一定存在,且只需要建一个无向图即可
typedef pair<int, int> pii;
const int N = 1000 + 10, INF = 0x3f3f3f3f;
struct edge
{
int to, cost, next;
}g[N*200];
struct node
{
int h, g, v;//f,g是估价函数中相应的值
friend bool operator< (node a, node b)
{
return a.h + a.g > b.h + b.g;
}
};
int cnt, head
, rhead
;
int dis
, num
;
bool vis
;
void init()
{
cnt = 0;
memset(head, -1, sizeof head);
memset(rhead, -1, sizeof rhead);
}
void add_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
void radd_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = rhead[v], rhead[v] = cnt++;
}
void dijkstra(int s, int t)
{
priority_queue<pii, vector<pii>, greater<pii> > que;
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
que.push(pii(0, s)), dis[s] = 0;
while(! que.empty())
{
int v = que.top().second; que.pop();
if(vis[v] == true) continue;
vis[v] = true;
for(int i = rhead[v]; i != -1; i = g[i].next)
{
int u = g[i].to;
if(dis[u] > dis[v] + g[i].cost)
{
dis[u] = dis[v] + g[i].cost;
que.push(pii(dis[u], u));
}
}
}
}
int a_star(int s, int t, int k)
{
if(s == t) k++;
if(dis[s] == INF) return -1;
priority_queue<node> que;
memset(num, 0, sizeof num);
node e;
e.v = s, e.g = 0, e.h = dis[s];
que.push(e);
while(! que.empty())
{
node p = que.top(); que.pop();
num[p.v]++;
if(num[p.v] > k) continue;//一个优化
if(num[t] == k) return p.g;
for(int i = head[p.v]; i != -1; i = g[i].next)
{
e.v = g[i].to, e.g = p.g + g[i].cost, e.h = dis[e.v];
que.push(e);
}
}
return -1;
}
int main()
{
int n, m;
while(~ scanf("%d%d", &n, &m))
{
init();
int a, b, c;
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c);
radd_edge(b, a, c);
}
int s, t, k;
scanf("%d%d%d", &s, &t, &k);//求从s到t的最短路
dijkstra(t, s); //求出从终点t到所有点的最短路
int ans = a_star(s, t, k);
printf("%d\n", ans);
}
return 0;
}


次短路:

//点下标1~n,求从1到n的次短路,一条边可以走多次
typedef pair<int, int> P;
typedef long long ll;
const int N = 5010;
struct edge
{
int to, cost, next;
}g[N*100];
int cnt, head
;
int dis1
, dis2
;
bool vis
;
void add_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
void dijkstra(int s)
{
memset(dis1, 0x3f, sizeof dis1);
memset(dis2, 0x3f, sizeof dis2);
priority_queue<P, vector<P>, greater<P> > que;
dis1[s] = 0;
que.push(P(dis1[s], s));
while(! que.empty())
{
P p = que.top(); que.pop();
int v = p.second;
if(dis2[p.second] < p.first) continue;
for(int i = head[v]; i != -1; i = g[i].next)
{
int u = g[i].to, d = p.first + g[i].cost;
if(dis1[u] > d)
{
swap(dis1[u], d);
que.push(P(dis1[u], u));
}
if(dis2[u] > d && dis1[u] < d)
{//当前条件限制的次短路严格小于最短路,若允许次短路等于最短路,改dis1[u]<=d
dis2[u] = d;
que.push(P(dis2[u], u));
}
}
}
}
int main()
{
int n, m, a, b, c;
while(~ scanf("%d%d", &n, &m))
{
cnt = 0;
memset(head, -1, sizeof head);
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c), add_edge(b, a, c);
}
dijkstra(1);
printf("%d\n", dis2
);
}
return 0;
}


//另外一个次短路模板
typedef pair<int, int> P;
typedef long long ll;
const int N = 5010, INF = 0x3f3f3f3f;
struct edge
{
int to, cost, next;
}g[N*100];
int cnt, head
;
int dis1
, dis2
;
bool vis
;
void add_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
void spfa(int s, int dis[])
{
memset(vis, 0, sizeof vis);
queue<int> que;
que.push(s), dis[s] = 0, vis[s] = true;
while(! que.empty())
{
int v = que.front(); que.pop();
vis[v] = false;
for(int i = head[v]; i != -1; i = g[i].next)
{
int u = g[i].to;
if(dis[u] > dis[v] + g[i].cost)
{
dis[u] = dis[v] + g[i].cost;
if(! vis[u]) que.push(u), vis[u] = true;
}
}
}
}
int main()
{
int n, m, a, b, c;
while(~ scanf("%d%d", &n, &m))
{
cnt = 0;
memset(head, -1, sizeof head);
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c), add_edge(b, a, c);
}
memset(dis1, 0x3f, sizeof dis1);
memset(dis2, 0x3f, sizeof dis2);
spfa(1, dis1);
spfa(n, dis2);
int res = INF;
for(int i = 1; i <= n; i++)
for(int j = head[i]; j != -1; j = g[j].next)
{
int u = g[j].to;
int tmp = dis1[i] + dis2[u] + g[j].cost;
if(tmp > dis1
&& tmp < res) res = tmp;//tmp >= dis1

}
printf("%d\n", res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: