P2169 正则表达式

基础图论的大集成者。

形式化题意

给定一个边带权的有向图,如果存在一个环,则环内任意点互相到达不花费代价,求 的最短路。

题解

看到环啪的一下就来缩点啊,很快啊。

首先缩点,变成一个 ,然后跑最短路就结束了。

可以用来练习同时打 的板子的练习(好像 可过?),关键在于能不能从无 的题面快速获取有效信息了。

AC Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// ----- Eternally question-----
// Problem: P2169 正则表达式
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2169
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Written by: Eternity
// Time: 2022-11-10 14:44:15
// ----- Endless solution-------

#include<bits/stdc++.h>
#define re register
typedef long long ll;
template<class T>
inline void read(T &x)
{
x=0;
char ch=getchar(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1){ read(x),read(x1...); }
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
template<>
inline void write(bool x){ std::cout<<x; }
template<>
inline void write(char c){ putchar(c); }
template<>
inline void write(char *s){ while(*s!='\0') putchar(*s++); }
template<>
inline void write(const char *s){ while(*s!='\0') putchar(*s++); }
template<class T,class ...T1>
inline void write(T x,T1 ...x1){ write(x),write(x1...); }
template<class T>
inline bool checkMax(T &x,T y){ return x<y?x=y,1:0; }
template<class T>
inline bool checkMin(T &x,T y){ return x>y?x=y,1:0; }
const int MAXN=2e5+10,MAXM=1e6+10;
int N,M;
struct G
{
int next,to,val;
}Edge[MAXM<<1];
int Head[MAXN],Total;
inline void addEdge(int u,int v,int w)
{
Edge[++Total]=(G){Head[u],v,w};Head[u]=Total;
// Edge[++Total]=(G){Head[v],u,w};Head[v]=Total;
}
int Dfn[MAXN],Low[MAXN],Stk[MAXN],Top,Cnt;
bool Ins[MAXN];
int Scc[MAXN],Sizc[MAXN],Sc;
void Tarjan(int x)
{
Dfn[x]=Low[x]=++Cnt,Stk[++Top]=x,Ins[x]=1;
for(int e=Head[x],v;e;e=Edge[e].next)
{
if(!Dfn[(v=Edge[e].to)])
{
Tarjan(v);
checkMin(Low[x],Low[v]);
}
else if(Ins[v]) checkMin(Low[x],Dfn[v]);
}
if(Dfn[x]==Low[x])
{
Scc[x]=++Sc;
while(Stk[Top]!=x)
{
Scc[Stk[Top]]=Sc,++Sizc[Sc];
Ins[Stk[Top]]=0,--Top;
}
Ins[x]=0,++Sizc[Sc],--Top;
}
}
struct Edges
{
int fr,to,val;
}Ed[MAXM];
struct Que
{
int x,d;
Que(int x=0,int d=0):x(x),d(d){}
bool operator<(const Que &x) const { return x.d<d; }
};
int Dist[MAXN];
bool Vis[MAXN];
inline void Dijkstra(int st)
{
std::priority_queue<Que>Q;
Q.push(Que(st,0));
memset(Dist,0x3f,sizeof(Dist)),Dist[st]=0;
memset(Vis,0,sizeof(Vis));
while(!Q.empty())
{
int u=Q.top().x;Q.pop();
if(Vis[u]) continue;
Vis[u]=1;
for(int e=Head[u],v;e;e=Edge[e].next)
{
v=Edge[e].to;
if(Dist[v]>Dist[u]+Edge[e].val)
{
Dist[v]=Dist[u]+Edge[e].val;
if(!Vis[v]) Q.push(Que(v,Dist[v]));
}
}
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(N,M);
for(int i=1,u,v,w;i<=M;++i)
{
read(u,v,w);addEdge(u,v,w);
Ed[i]=(Edges){u,v,w};
}
for(int i=1;i<=N;++i) if(!Dfn[i]) Tarjan(i);
memset(Head,0,sizeof(Head)),Total=0;
for(int i=1;i<=M;++i)
{
if(Scc[Ed[i].fr]==Scc[Ed[i].to]) continue;
addEdge(Scc[Ed[i].fr],Scc[Ed[i].to],Ed[i].val);
}
Dijkstra(Scc[1]);
write(Dist[Scc[N]]);
return 0;
}
/*

*/