看到洛谷P2169有一道julao(一看就是标题党)出的题目,考察缩点+最短路。
很多julao用了Tarjan+重新建图,但是本蒟蒻所用的Kosaraju算法不需要重新建图,只需要把在同一强连通分量内的每一条边边权改为零即可。
#pragma GCC optimize(2)
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=200005,MAXM=1000005;
int n,m,nxt[MAXM],rnxt[MAXM],first[MAXN],rfirst[MAXN],go[MAXM],rgo[MAXM],tot=0,fv[MAXN];
int vst[MAXN],val[MAXM];
int ru,rv,rw,dis[MAXN];
bool dvis[MAXN];
struct node//用于Dijkstra
{
int pos,dis;
node(const int& POS,const int& DIS)
{
pos=POS;
dis=DIS;
}
bool operator<(const node& anth)const
{
return dis>anth.dis;
}
};
inline void ins(int u,int v,int w)
{
nxt[++tot]=first[u];first[u]=tot;go[tot]=v;
rnxt[tot]=rfirst[v];rfirst[v]=tot;rgo[tot]=u;
val[tot]=w;
}
void dfs1(int u)
{
vst[u]=true;
for(int e=first[u];e;e=nxt[e])
{
if(!vst[go[e]])dfs1(go[e]);
}
fv[++tot]=u;
}
void dfs2(int u)
{
vst[u]=tot;//tot现在表示已找到的强连通分量个数,vst相等代表在同一个强连通分量
for(int e=rfirst[u];e;e=rnxt[e])
{
if(vst[rgo[e]]==tot)val[e]=0;//在同一个强连通分量,边权改为零
if(!vst[rgo[e]])
{
val[e]=0;//在同一个强连通分量,边权改为零
dfs2(rgo[e]);
}
}
}
void kosaraju()
{
tot=0;
for(int i=1;i<=n;i++)if(!vst[i])dfs1(i);
memset(vst,0,(n<<2)+4);
tot=0;
for(int i=n;i;i--)if(!vst[fv[i]])tot++,dfs2(fv[i]);
}
void dijkstra()//蒟蒻不会SPFA
{
int s=1;
for(int i=1;i<=n;i++)dis[i]=2147483647;
dis[s]=0;
priority_queue<node>Q;//标准模版库大法好
Q.push(node(s,0));
while(!Q.empty())
{
node v=Q.top();Q.pop();
if(dvis[v.pos])continue;
dvis[v.pos]=true;
for(int e=first[v.pos];e;e=nxt[e])
{
int u=go[e];
if(dis[u]>dis[v.pos]+val[e])
{
dis[u]=dis[v.pos]+val[e];
if(!dvis[u])Q.push(node(u,dis[u]));
}
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=0;i<m;i++)cin>>ru>>rv>>rw,ins(ru,rv,rw);
kosaraju();
dijkstra();
cout<<dis[n]<<endl;
return 0;
}