链接:https://nanti.jisuanke.com/t/42388
题意:n个点,x条无向边,y条有向边(存在负边权),一个起点s,然后求s到剩余点的最短路
题解:这题卡spfa......
然后看题解,写的用连通块加上Dijkstra,Dijkstra还能写负边权(???)
相同的连通块之内用Dijkstra,不同的Dijkstra用遍历........
#include <bits/stdc++.h>
using namespace std;
int n, x, y, s;
const int MAXN = 2e5 + 50;
typedef pair<int, int> pii;
#define mp make_pair
int head[MAXN], tot;
struct Edge
{
int nex, to, dis;
}eg[MAXN];
void addedge(int a, int b, int c)
{
eg[++tot] = {head[a], b, c};
head[a] = tot;
}
void add(int a, int b, int c)
{
addedge(a, b, c);
addedge(b, a, c);
}
vector<int> bel[MAXN];
int co[MAXN], cnt;//联通块的颜色、联通块的数量
void dfs(int v, int col)//dfs给联通块染色
{
co[v] = col;
bel[col].push_back(v);
for(int i = head[v]; i; i = eg[i].nex)
{
int to = eg[i].to;
if(!co[to]) dfs(to, col);
}
}
int deg[MAXN], dis[MAXN];//每个联通块的入度、单源最短路径
int vis[MAXN];
queue<int> que;//拓扑排序:入度为0的联通块入队
priority_queue<pii, vector<pii>, greater<pii> > pq;
void Dijkstra()
{
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
for(int i = 1; i <= cnt; i++) if(!deg[i]) que.push(i);
while(!que.empty())//topological-sort
{
int u = que.front(); que.pop();
int sz = bel[u].size();
for(int i = 0; i < sz; i++) pq.push(mp(dis[bel[u][i]], bel[u][i]));
while(!pq.empty())//Dijkstra
{
int x = pq.top().second; pq.pop();
if(vis[x]) continue;
vis[x] = 1;
for(int i = head[x]; i; i = eg[i].nex)
{
int to = eg[i].to;
if(co[x] == co[to] && dis[to] > dis[x] + eg[i].dis)
{
dis[to] = dis[x] + eg[i].dis;
pq.push(mp(dis[to], to));
}
if(co[x] != co[to])
{
dis[to] = min(dis[to], dis[x] + eg[i].dis);
deg[co[to]]--;
if(!deg[co[to]]) que.push(co[to]);
}
}
}
}
}
int main()
{
scanf("%d%d%d%d", &n, &x, &y, &s);
for(int i = 1, a, b, c; i <= x; i++)
{
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
for(int i = 1; i <= n; i++) if(!co[i]) dfs(i, ++cnt);
for(int i = 1, a, b, c; i <= y; i++)
{
scanf("%d%d%d", &a, &b, &c);
addedge(a, b, c);
deg[co[b]]++;
}
Dijkstra();
for(int i = 1; i <=n; i++)
{
if(dis[i] > 1e9) puts("NO PATH");
else printf("%d\n", dis[i]);
}
return 0;
}

京公网安备 11010502036488号