洛谷P2169(正则表达式)题解(不用Tarjan)

点此看题

看到洛谷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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值