最短路
Dijkstra(狄杰斯特拉)算法
T(n)=O(n^2)
void dijkstra()
{
for (int i = 1; i <= n; i++)
{
flag[i] = 0;
road[i] = uv[1][i];
}
road[1] = 0;
flag[1] = 1;
for (int i = 1; i < n; i++)
{
int minn = 0x7fffff;
int t;
for (int j = 1; j <= n; j++)
if (flag[j] == 0 && road[j] < minn)
{
t = j;
minn = road[j];
}
flag[t] = 1;
for (int k = 1; k <= n; k++)
road[k] = min(road[k], road[t] + uv[t][k]);
}
}
//记录路径
void dfs(int v, int len)
{
if (v == 1)
return;
for (int i = 1; i <= n; i++)
if (uv[i][v] != 0x7fffff)
if (road[v] - uv[i][v] == road[i])
{
x[++o] = v;
y[o] = i;
dfs(i, road[i]);
return;
}
}
堆优化+记录路径+记录路径数
复杂度:O((V+E)logE)----V为边数,E为点数
ll n,m,s,e,tot;
ll head[maxn], tot, dis[maxn], vis[maxn],pre[maxn],cnt[maxn];
priority_queue<pair<ll,ll> >que;//格式化文档时这里易错
struct Edges
{
ll from,to,dis,next;
}edges[maxm];
void add(ll x,ll y,ll dis)
{
edges[++tot].next=head[x];
edges[tot].to=y;
edges[tot].dis=dis;
head[x]=tot;
}
void Path(ll i)
{
if (pre[i] == -1)
return;
else
Path(pre[i]);
printf("%lld ", pre[i]);
}
void dij()
{
que.push(make_pair(0,s));
while(!que.empty())
{
ll u=que.top().second;
que.pop();
if(vis[u]) continue;
vis[u]=1;
for(ll i=head[u];i;i=edges[i].next)
{
ll v=edges[i].to;
if(dis[v]>dis[u]+edges[i].dis)
{
dis[v]=dis[u]+edges[i].dis;
que.push(make_pair(-dis[v],v));//pair先比较第一个,后比较第二个
//改成dis[v]传可按降序出队列,解决最长路问题
}
else if(dis[v] == dis[u] + edges[i].dis)
{
cnt[v]+=cnt[u];
}
}
}
}
int main()
{
// DEBUG;
while(!que.empty()) que.pop();
tot=0;
memset(head,0,sizeof(head));
memset(dis,INF,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(cnt, 0, sizeof(cnt));
memset(pre, -1, sizeof(pre));
scanf("%lld%lld%lld%lld",&n,&m,&s,&e);
for(ll i=1;i<=m;i++)
{
ll v,u,dis;
scanf("%lld%lld%lld",&v,&u,&dis);
add(v,u,dis);
add(u,v,dis);
}
dis[s]=0;
cnt[s]=1;
dij();
printf("%lld\n",dis[e]);
printf("%lld\n", cnt[e]);
Path(e);
printf("%lld\n", e);
}
floyd算法
多源最短路
T(n)=O(n^3)
ll n, m,s,d;
ll dis[maxn][maxn], va[maxn][maxn], p[maxn][maxn];
ll arr[maxn];
void floyd()
{
for (ll k = 1; k <= n; k++)
{
for (ll u = 1; u <= n; u++)
{
for (ll v = 1; v <= n; v++)
{
if (dis[u][v] > dis[u][k] + dis[k][v])
{
dis[u][v] = dis[u][k] + dis[k][v];
va[u][v] = va[u][k] + va[k][v];
p[u][v] = p[u][k];
}
else if (dis[u][v] == dis[u][k] + dis[k][v] && va[u][v] < va[u][k] + va[k][v])
{
va[u][v] = va[u][k] + va[k][v];
p[u][v] = p[u][k];
}
}
}
}
}
int main()
{
// DEBUG;
scanf("%lld%lld%lld%lld", &n, &m,&s,&d);
for (ll i = 1; i <= n; i++)
{
for (ll j = 1; j <= n; j++)
{
p[i][j] = j;
va[i][j] = 0;
if (i != j)
dis[i][j] = INF;
else
dis[i][j] = 0;
}
}
for (ll i = 1; i <= m; i++)
{
ll u, v, w, val;
scanf("%lld%lld%lld%lld", &u, &v, &w);
dis[u][v] = w;
va[u][v] = val;
dis[v][u] = w;
va[v][u] = val;
}
floyd();
ll st, minres = INF;
ll k;
scanf("%lld", &k);
for (ll i = 1; i <= k; i++)
{
scanf("%lld", &arr[i]);
}
for (ll i = 1; i <= n; i++)
{
ll res = 0;
ll u = i;
for (ll j = 1; j <= n; j++)
{
ll v = j;
res = max(dis[u][v], res);
}
if (res < minres)
{
minres = res;
st = u;
}
}
printf("%lld\n", st);
for (ll i = 1; i <= k; i++)
{
ll v = arr[i];
printf("%lld", st);
ll u = st;
while (u != v)
{
printf("->%lld", p[u][v]);
u = p[u][v];
}
printf("\n");
printf("%lld %lld\n", dis[st][v], va[st][v]);
}
return 0;
}
SPFA算法
复杂度:O(E)~O(VE)
ll head[maxn], tot, dis[maxn], vis[maxn], pre[maxn], cnt[maxn],cnt1[maxn];
ll n, m, s, e, x, y, z;
queue<ll> q; //用标准队列
struct Edge
{
ll next, to, dis;
} edges[maxn]; //链式前向星存图
void add(ll x, ll y, ll z)
{
edge[++tot].next = head[x];
edge[tot].to = y;
edge[tot].dis = z;
head[x] = tot;
}
// 打印路径
void Path(ll i)
{
if (pre[i] == -1)
return;
else
Path(pre[i]);
printf("%lld ", pre[i]);
}
void spfa()
{
q.push(s);
vis[s] = 1;//每次入队,vis标记为 1
while (!q.empty())
{
x = q.front();
q.pop();
vis[x] = 0;//每次入队,vis标记为 0
for (ll i = head[x]; i; i = edge[i].next)
{
y = edge[i].to;
if (dis[y] > dis[x] + edge[i].dis)
{
dis[y] = dis[x] + edge[i].dis;
pre[y] = x;
cnt[y] = cnt[x];
cnt1[y]++;
if(cnt1[y]>n+10) return -1;//表示存在负环
if (!vis[y])
{
vis[y] = 1;
q.push(y);
}
}
else if (dis[y] == dis[x] + edge[i].dis)
{
cnt[y] += cnt[x];
}
}
}
}
int main()
{
scanf("%lld%lld%lld", &n, &m, &s);
for (ll i = 1; i <= m; i++)
{
scanf("%lld%lld%lld", &x, &y, &z);
add(x, y, z);
}
memset(cnt, 0, sizeof(cnt)); //记录最短路径数
memset(pre, -1, sizeof(pre));
memset(dis, INF, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[s] = 0; //初始化
cnt[s] = 1;
spfa();
for (ll i = 1; i <= n; i++)
{
if (s == i)
printf("0 ");
else printf("%lld ", dis[i]);
}
printf("%lld\n", cnt[e]);
Path(e);
printf("%lld\n", e);
return 0;
}
拓扑排序
复杂度:O(V+E)
ll n,m;
ll ind[maxn];
ll res[maxn];
vector<ll> to[maxn];
queue<ll> que;
int main()
{
// DEBUG;
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=m;i++)
{
ll u,v;
scanf("%lld%lld",&u,&v);
to[u].push_back(v);
ind[v]++;
}
for(ll i=1;i<=n;i++)
{
if(ind[i]==0) que.push(i);
}
ll pos=0;
while(!que.empty())
{
ll u=que.front();
que.pop();
res[++pos]=u;
for(auto v:to[u])
{
ind[v]--;
if(ind[v]==0) que.push(v);
}
}
for(ll i=1;i<=n;i++)
{
printf("%lld\n",res[i]);
}
}
Tarjan
struct Edge
{
ll next, to, dis, from;
double f;
} edges[maxm], E[maxm];
ll dfn[maxn], low[maxn], n, m, color[maxn], col = 0, w[maxn], s;
ll stackk[maxn], heads[maxn], visit[maxn], cnt, tot, index1, times;
ll H[maxn], tot1, dis[maxn], vis[maxn];
ll e, x, y, z;
priority_queue<pair<ll, ll>> que;
void add(ll x, ll y)
{
edges[++tot].next = heads[x];
edges[tot].from = x;
edges[tot].to = y;
heads[x] = tot;
return;
}
void add2(ll x, ll y, ll z)
{
E[++tot1].next = H[x];
E[tot1].to = y;
E[tot1].dis = z;
H[x] = tot1;
}
void tarjan(ll x)
{
dfn[x] = low[x] = ++times;
visit[x] = 1;
stackk[++index1] = x;
for (ll i = heads[x]; i; i = edges[i].next)
{
if (!dfn[edges[i].to])
{
tarjan(edges[i].to);
low[x] = min(low[x], low[edges[i].to]);
}
else if (visit[edges[i].to])
{
low[x] = min(low[x], dfn[edges[i].to]);
}
}
if (low[x] == dfn[x])
{
col++;
do
{
color[stackk[index1]] = col;
visit[stackk[index1]] = 0;
index1--;
} while (x != stackk[index1 + 1]);
}
}
int main()
{
memset(heads, 0, sizeof(heads));
ll n, m;
scanf("%lld%lld", &n, &m);
ll x, y;
for (ll i = 1; i <= m; i++)
{
scanf("%lld%lld", &x, &y);
add(x, y);
}
for (ll i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i);
for (ll i = 1; i <= m; i++)
{
if (color[edges[i].to] != color[edges[i].from])
{
ll id = color[edges[i].to];
w[id] += edges[i].dis;
}
else
{
ll x = color[edges[i].from], y = color[edges[i].to];
add2(x, y, edges[i].dis);
}
}
return 0;
}