题意:
给出一个n个结点m条边有向图,可能有负权边;
但是存在负权边a->b则不会有某个路径可以从b到a;
求一个源点s到所有点的最短路(无解输出"NO PATH");
n<=25000,m<=150000;
题解:
高高兴兴的写了一发spfa,复杂度O(km),k<=2嘛;
然后就TLE了,这题丧心病狂的把spfa卡掉了;
这时候理所当然的想到了dij+heap,写到一半想起来dij并不支持负权边;
所以这个不是一个简单的单源最短路问题;
题中有一个重要条件就是负权边不会在环中;
我本以为只是排除了负权环的存在,但是事实上,这个性质使负权边不可能在任何的强连通分量内;
那么每个强连通分量内的最短路可以用dij实现;
强连通分量缩点后是DAG,直接DP传一下进入强连通分量的最短路就可以了;
时间复杂度O(nlogn);
HINT:
每次dij时是没有源点的,直接将所有点加入heap做最短路;
不可到达的强连通分量不能将最短路下传,防止在最后判断是否为inf时错误;
USACO数据还是naive,知道正解就一A了;
为了写这题还去学了dij+heap然后并过不了;
最近写的代码越来越长是错觉吗。。。
代码:
#include<queue>
#include<stack>
#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 25500
#define pr pair<int,int>
using namespace std;
vector<int>to[N],val[N],son[N];
priority_queue<pr,vector<pr >,greater<pr > >poq;
queue<int>q;
stack<int>st;
int f[N],dis[N];
int deep[N],low[N],belong[N],in[N],cnt,tot;
bool ins[N],cov[N],vis[N];
void tarjan(int x)
{
deep[x]=low[x]=++cnt;
st.push(x),ins[x]=1;
int i,y;
for(i=0;i<to[x].size();i++)
{
if(!deep[y=to[x][i]])
tarjan(y),low[x]=min(low[x],low[y]);
else if(ins[y])
low[x]=min(low[x],deep[y]);
}
if(deep[x]==low[x])
{
tot++;
int k;
do
{
k=st.top(),st.pop();
ins[k]=0;
belong[k]=tot;
son[tot].push_back(k);
}while(k!=x);
}
}
void dij(int x)
{
int i,j,k,y;
for(i=0;i<son[x].size();i++)
poq.push(pr(dis[son[x][i]],son[x][i]));
while(!poq.empty())
{
k=poq.top().second;
poq.pop();
if(vis[k]) continue;
vis[k]=1;
for(i=0;i<to[k].size();i++)
{
if(belong[y=to[k][i]]==x)
if(dis[y]>dis[k]+val[k][i])
{
dis[y]=dis[k]+val[k][i];
poq.push(pr(dis[y],y));
}
}
}
}
int main()
{
int n,m1,m2,s,i,j,k,x,y,v;
scanf("%d%d%d%d",&n,&m1,&m2,&s);
for(i=1;i<=m1;i++)
{
scanf("%d%d%d",&x,&y,&v);
to[x].push_back(y);
val[x].push_back(v);
to[y].push_back(x);
val[y].push_back(v);
}
for(i=1;i<=m2;i++)
{
scanf("%d%d%d",&x,&y,&v);
to[x].push_back(y);
val[x].push_back(v);
}
for(i=1;i<=n;i++)
if(!deep[i])
tarjan(i);
for(x=1;x<=n;x++)
{
for(i=0;i<to[x].size();i++)
{
if(belong[y=to[x][i]]!=belong[x])
{
in[belong[y]]++;
}
}
}
for(i=1;i<=tot;i++)
if(!in[i])
q.push(i);
memset(dis,0x3f,sizeof(dis));
dis[s]=0,cov[belong[s]]=1;
while(!q.empty())
{
x=q.front(),q.pop();
if(cov[x])
dij(x);
for(j=0;j<son[x].size();j++)
{
k=son[x][j];
for(i=0;i<to[k].size();i++)
{
if(belong[y=to[k][i]]!=x)
{
if(cov[x])
{
cov[belong[y]]=1;
dis[y]=min(dis[k]+val[k][i],dis[y]);
}
in[belong[y]]--;
if(!in[belong[y]])
q.push(belong[y]);
}
}
}
}
for(i=1;i<=n;i++)
{
if(dis[i]==0x3f3f3f3f)
puts("NO PATH");
else
printf("%d\n",dis[i]);
}
return 0;
}