最短路记录路径 POJ 2457
Description
m条单向路,n个点(1~n)
求从1到n的最短路,不存在输出“-1”,存在则输出路径
Floyd
较为特殊,数组pre[i][j]存从i到j的最短路径上i后面的第一个点
当然对于此题Floyd已超时了,但算法是对的
Code of Floyd
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int m, n;
int mp[1005][1005];
int pre[1005][1005];
///pre[i][j]存从i到j的最短路径上i后面的第一个点
void init()
{
for(int i = 0; i <= n; ++i)
for(int j = 0; j <= n; ++j)
{
mp[i][j] = (i == j ? 0: INF);
pre[i][j] = j;
}
}
void floyd()
{
vector<int> ans;
for(int k = 1; k <= n; ++k)///我无语了,又写成了++i
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
if(mp[i][j] > mp[i][k] + mp[k][j])
{
mp[i][j] = mp[i][k] + mp[k][j];
pre[i][j] = pre[i][k];
}
if(mp[1][n] == INF)
cout << "-1" << '\n';
else
{
vector<int> ans;
ans.push_back(1);
int pos = pre[1][n];
while(pos != n)
{
ans.push_back(pos);
pos = pre[pos][n];
}
ans.push_back(n);
int sz = ans.size();
cout << sz << '\n';
for(int i = 0; i < sz; ++i)
cout << ans[i] << '\n';
}
return ;
}
int main()
{
while(~scanf("%d%d", &m, &n))
{
init();
int there, here;
for(int i = 0; i < m; ++i)
{
scanf("%d%d", &there, &here);
mp[there][here] = 1;
}
floyd();
}
return 0;
}
Dijkstra
nodepre[N],这种最短路的记录路径,就像BFS的记录路径pre,像最长递增子序列的记录路径pre,像链式前向星的pre。
Code of Dijkstra
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int m, n;
bool vis[1005];
int head[1005], dis[1005];
int nodepre[1005];
///路径都是pre存(由后推前),而非nxt(由前推后)的原因:
///更新方向:由前向后,一点更新多点
///即:一点有多个nxt,却只有一个"有实际意义的"pre
int cnt;
struct edge
{
int from, to, w, pre;
} a[50005];
void add(int from, int to, int w)
{
a[cnt].from = from;
a[cnt].to = to;
a[cnt].w = w;
a[cnt].pre = head[from];
head[from] = cnt;
cnt++;
}
void init()
{
cnt = 0;
for(int i = 0; i <= n; ++i)
{
dis[i] = INF;
vis[i] = 0;
head[i] = -1;
nodepre[i] = -1;
}
}
void Dijkstra(int start)
{
dis[start] = 0;
int pos = start;
int mmin;
while(pos != -1)
{
for(int i = head[pos]; ~i; i = a[i].pre)
{
if(vis[ a[i].to ])
continue;
if(dis[ a[i].to ] == INF || dis[ a[i].to ] > dis[pos] + a[i].w)
{
dis[ a[i].to ] = dis[pos] + a[i].w;
nodepre[ a[i].to ] = pos;
}
}
vis[pos] = 1;
pos = -1;
mmin = -1;
for(int i = 1; i <= n; ++i)
if(!vis[i] && dis[i] != INF && (mmin == -1 || mmin > dis[i]))
{
mmin = dis[i];
pos = i;
}
}
if(dis[n] == INF)
{
cout << "-1" << '\n';
return ;
}
vector<int> ans;
pos = n;
while(nodepre[pos] != -1)
{
ans.push_back(pos);
pos = nodepre[pos];
}
ans.push_back(start);
int sz = ans.size();
cout << sz << '\n';
for(int i = sz - 1; i >= 0; --i)
cout << ans[i] << '\n';
return ;
}
int main()
{
while(~scanf("%d%d", &m, &n))
{
init();
int there, here;
for(int i = 0; i < m; ++i)
{
scanf("%d%d", &there, &here);
add(there, here, 1);
}
Dijkstra(1);
}
return 0;
}
Bellman_Ford
同Dijkstra普通记录路径方法
Code of Bellman_Ford
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int m, n, dis[1005], nodepre[1005];
int cnt;
struct edge
{
int from, to, w;
} a[50005];
void add(int from, int to, int w)
{
a[cnt].from = from;
a[cnt].to = to;
a[cnt].w = w;
cnt++;
}
bool Bellman_Ford(int start)
{
dis[start] = 0;
int tot = n;
while(tot--)
{
bool flag = 0;
for(int i = 0; i < cnt; ++i)
if(dis[ a[i].to ] > dis[ a[i].from ] + a[i].w)
{
flag = 1;
dis[ a[i].to ] = dis[ a[i].from ] + a[i].w;
nodepre[ a[i].to ] = a[i].from;
}
if(!flag)
break;
}
for(int i = 0; i < cnt; ++i)
if(dis[ a[i].to ] > dis[ a[i].from ] + a[i].w)
return 0;
if(dis[n] == INF)
cout << "-1" << '\n';
else
{
int pos = n;
vector<int> ans;
while(pos != -1)
{
ans.push_back(pos);
pos = nodepre[pos];
}
int sz = ans.size();
cout << sz << '\n';
for(int i = sz - 1; i >= 0; --i)
cout << ans[i] << '\n';
}
return 1;
}
int main()
{
while(~scanf("%d%d", &m, &n))
{
cnt = 0;
memset(dis, INF, sizeof(dis));
memset(nodepre, -1, sizeof(nodepre));
int there, here;
for(int i = 0; i < m; ++i)
{
scanf("%d%d", &there, &here);
add(there, here, 1);
}
if(Bellman_Ford(1))
continue;
}
return 0;
}
spfa
同Dijkstra普通记录路径方法
Code of spfa
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int m, n;
bool vis[1005];
int head[1005], dis[1005], times[1005], tot, sum;
int nodepre[1005];
int cnt;
struct edge
{
int from, to, w, pre;
} a[50005];
void add(int from, int to, int w)
{
a[cnt].from = from;
a[cnt].to = to;
a[cnt].w = w;
a[cnt].pre = head[from];
head[from] = cnt;
cnt++;
}
void init()
{
cnt = 0;
for(int i = 0; i <= n; ++i)
{
dis[i] = INF;
vis[i] = 0;
times[i] = 0;
head[i] = -1;
nodepre[i] = -1;
}
}
bool spfa(int start)
{
dis[start] = 0;
deque<int> q;
q.push_front(start);
vis[start] = 1;
tot = 1, sum = 0;
while(q.size())
{
int first = q.front();
q.pop_front();
vis[first] = 0;
sum -= dis[first];
tot--;
for(int i = head[first]; ~i; i = a[i].pre)
{
int t = a[i].to;
if(dis[t] > dis[first] + a[i].w)
{
dis[t] = dis[first] + a[i].w;
nodepre[t] = first;
if(!vis[t])
{
vis[t] = 1;
if(q.empty() || dis[q.front()] < dis[t] || dis[t] * tot >= sum)
q.push_back(t);
else
q.push_front(t);
sum += dis[t];
tot++;
if(++times[t] >= n)
return 0;
}
}
}
}
if(dis[n] == INF)
cout << "-1" << '\n';
else
{
int pos = n;
vector<int> ans;
while(pos != -1)
{
ans.push_back(pos);
pos = nodepre[pos];
}
int sz = ans.size();
cout << sz << '\n';
for(int i = sz - 1; i >= 0; --i)
cout << ans[i] << '\n';
}
return 1;
}
int main()
{
while(~scanf("%d%d", &m, &n))
{
init();
int there, here;
for(int i = 0; i < m; ++i)
{
scanf("%d%d", &there, &here);
add(there, here, 1);
}
if(spfa(1))
continue;
}
return 0;
}