道路与航线
【题意】给定n个点的图,正权无向边,正负权有向边,保证对有向边(u,v),v无法到达u,求起点出发到达所有点的最短距离。
题目很朴素,目的就是理解spfa和dijkstra各自的限制。
dijkstra的限制是负边和环,spfa算是暴力。。限制是时间复杂度
这题保证了负数边权的特殊,整个图可被分为数个由负边连起来的连通块。联通块内部是全部都是正权。
那就对连通块跑dijkstra,把这些连通块看作点然后对整张图跑spfa
算是优劣结合吧。。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
char c=getchar();ll a=0,b=1;
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll t,r,p,s;
ll head1[5000001],tot1,cnt;
ll col[25001],dist[2501],inconb[2501];bool flag[2501];
struct edge
{
ll next,to,v;
}e1[5000001];
inline void add1(ll i,ll j,ll v)
{
e1[++tot1].next=head1[i];
e1[tot1].to=j;
e1[tot1].v=v;
head1[i]=tot1;
}
void dfs(ll x,ll now)
{
col[x]=now;
for(ll i=head1[x];i!=0;i=e1[i].next)
{
ll u=e1[i].to;
if(col[u]!=0)continue;
dfs(u,now);
}
}
ll q[25001],top=0,End=0;
void dijkstra(ll start,ll val)
{
dist[start]=val;
priority_queue<pair<ll,ll> > q1;
q1.push({dist[start],start});
while(!q1.empty())
{
ll x=q1.top().second;
if(flag[x])continue;
flag[x]=1;
q1.pop();
for(ll i=head1[x];i!=0;i=e1[i].next)
{
ll u=e1[i].to;
if(col[u]!=col[start])
{
inconb[col[u]]--;
dist[u]=min(dist[u],dist[x]+e1[i].v);
if(inconb[col[u]]==0)
{
q[++top]=u;
}
}
if(dist[u]>dist[x]+e1[i].v)
{
dist[u]=dist[x]+e1[i].v;
q1.push({dist[u],u});
}
}
}
}
void spfa()
{
q[++top]=s;
memset(flag,0,sizeof(flag));
memset(dist,0x3f,sizeof(dist));
dist[s]=0;
while(top!=End)
{
ll x=q[++End];
dijkstra(x,dist[x]);
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
t=read(),r=read(),p=read(),s=read();
for(ll i=1;i<=r;i++)
{
ll a=read(),b=read(),c=read();
add1(a,b,c);
add1(b,a,c);
}
for(ll i=1;i<=t;i++)
{
if(col[i]==0)
{
dfs(i,++cnt);
}
}
for(ll i=1;i<=p;i++)
{
ll a=read(),b=read(),c=read();
add1(a,b,c);
inconb[col[b]]++;
}
spfa();
for(ll i=1;i<=t;i++)
{
if(dist[i]<1e9)
printf("%d\n",dist[i]);
else
printf("NO PATH\n");
}
return 0;
}
好烦,acwing上T了,难受,不知道怎么改了,能改的都改了。。
好烦。
就这样吧,下一题