根据题目,很容易发现这是个最短路问题,然后就蒙了(bushi
通读题目,我们发现从一个点到另外一个点无非有两种连接方式,要么是边权为正的无向边,要么是边权可正可负的单向边。因此我们可以进行以下操作:
1、将边权为正的无向边构成一个个单独的连通块,把边权值未知的有向边当做连接的边,使得整个图形看起来如同大点(单独连通块)构成的图。而每个连通块中,都会有有限个点。进行一个大图的跑。
ps:注意题目中说恐怖分子那里,保证了块的存在,也保证了如果能飞则必定不是同一个连通块。
由于边权为负,我们此处使用拓扑排序,保证所有的点相连。
对于连通块中,我可以用dij跑出最小值。
好i的,整个题抽象完成,实践开始:
1、第一步,我们建图,同时开辟id数组存储每个点属于哪个连通块,用vector的block一维数组存每个连通块的点,使其加入。
2.分连通块。dfs每个连通块。
3.考虑连通块的入度,跑拓扑排序。
4.进行每个块中的每个点的dij,找出dij的每个点最优解
5.输出即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
const int N = 2e5 + 10;
const int M = 150010;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
int n,mr,mp,S;
int h[N],e[M],ne[M],w[M],idx;
int id[N];//存储每个连通块
vector<int>block[N];//存储每个联通块中的点
int dist[N];
bool st[N];
int bcnt;
int din[N];
queue<int>q;
void add(int a,int b,int c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}
void dfs(int u,int bid)
{
id[u] = bid;
block[bid].push_back(u);//加入这个连通块内
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(!id[j])
dfs(j,bid);
}
}
void dij(int bid)
{
priority_queue<PII,vector<PII>,greater<PII> >heap;
for(auto ver : block[bid])
{
heap.push({dist[ver],ver});
}
while(heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.second;
int dis = t.first;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver]; ~i; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
if(id[j] == id[ver])
{
heap.push({dist[j],j});
}
}
if(id[j] != id[ver] && --din[id[j]] == 0)
{
q.push(id[j]);
}
}
}
}
void topsort()
{
memset(dist,0x3f,sizeof dist);
dist[S] = 0;
for(int i = 1; i <= bcnt; i ++)
{
if(!din[i]) q.push(i);
}
while(q.size())
{
int t = q.front();
q.pop();
dij(t);
}
}
int main()
{
scanf("%d%d%d%d",&n,&mr,&mp,&S);
memset(h,-1,sizeof h);
while(mr --)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
for(int i = 1;i <= n; i ++)
{
if(!id[i])
dfs(i,++ bcnt);
}
while(mp--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
din[id[b]] ++;
}
topsort();
for(int i = 1;i <= n; i ++)
if(dist[i] > INF / 2) puts("NO PATH");
else printf("%d\n",dist[i]);
system("pause");
return 0;
}