P2656 题解
看到讨论区里说 dijkstra 不能求最长路,其实是可以求的,正好题解里没有一篇用 dijkstra 的,那我就来水发一篇吧
Description
给定一个
Solution
Tarjan 缩点不用说,在一个强连通分量里我们可以把每条边的边权“榨干”,也就是重复走直到这个强连通分量里的每一条边对答案不再有贡献为止。
而众所周知,dij 在求最长路时是不能有正环的,否则会陷在正环中无限循环。而 Tarjan 缩点之后就很好地避免了这个问题,因为一个正环一定在一个强连通分量中,在缩点之后就被缩成了一个点。至于具体实现,只需将原来求最短路中的松弛条件 dis[y] > dis[x] + e[i].w 改为 dis[y] < dis[x] + en[i].w + val[y] 就可以了,其中 val[y] 表示编号为
Code
完整版高清有注释代码:
#include<iostream>
#include<queue>
#include<stack>
#define maxn 80004
#define maxm 200005
#define inf 0x7fffffff
using namespace std;
int n, m, s;
double re[maxm];
int head[maxn], cnt, headn[maxn], cntn;
struct edge {
int to, next, w, maxx;
double r;
}e[maxm], en[maxm];
inline void add(int u, int v, int w, double r, int maxx) {
e[++ cnt] = (edge){v, head[u], w, maxx, r};
head[u] = cnt;
}//其实那个 r 没有什么用,但我懒得改了
inline void addn(int u, int v, int w, double r, int maxx) {
en[++ cntn] = (edge){v, headn[u], w, maxx, r};
headn[u] = cntn;
}
inline int maxx(int w, int r) {
int now = (r * w) / 10; int ans = w;
while(now) {
ans += (int)now;
now = (r * now) / 10;//避免精度问题
}
return ans;
}//求这条边所能贡献的最大边权和
stack<int> st;
int dfn[maxn], low[maxn], ind, belong[maxn], col, val[maxn];
bool vis[maxn];
void tar(int u) {
dfn[u] = low[u] = ++ ind;
st.push(u); vis[u] = 1;
for(int i = head[u], v; i; i = e[i].next) {
v = e[i].to;
if(dfn[v] == 0) {
tar(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]) low[u] = min(low[u], low[v]);
}
if(low[u] == dfn[u]) {
++ col; int t = -1;
while(t != u) {
t = st.top(); st.pop();
belong[t] = col; vis[t] = 0;
}
}
}
struct node {
int pos, dis;
bool friend operator < (node a, node b) {return a.dis > b.dis;}
//注意求最长路时重定义运算符是是大于号
};
priority_queue<node> q;
bool viss[maxn];
int dis[maxn];
void dij() {
for(int i = 1; i <= col; ++ i) dis[i] = 0;
s = belong[s]; dis[s] = val[s];//走到起点时最大答案就是这个强连通分量的最大边权之和
q.push((node){s, dis[s]});
while(!q.empty()) {
node tmp = q.top(); q.pop();
int x = tmp.pos;
if(vis[x]) continue;
for(int i = headn[x]; i; i = en[i].next) {
int y = en[i].to;
if(dis[y] < dis[x] + en[i].w + val[y]) {//dijkstra魔改的地方
dis[y] = dis[x] + en[i].w + val[y];
if(!vis[y]) {
q.push((node){y, dis[y]});
}
}
}
}
}
int main() {
ios :: sync_with_stdio(0); cin.tie(0); cout.tie(0);//读入优化
cin >> n >> m; double r;
for(int i = 1, u, v, w; i <= m; ++ i) {
cin >> u >> v >> w >> r;
add(u, v, w, r, maxx(w, r * 10));
}
cin >> s;
for(int i = 1; i <= n; ++ i) {
if(dfn[i] == 0) tar(i);
}
for(int j = 1; j <= n; ++ j) {
for(int i = head[j], v; i; i = e[i].next) {
v = e[i].to;
if(belong[j] == belong[v]) {
val[belong[j]] += e[i].maxx;
continue;
}
addn(belong[j], belong[v], e[i].w, e[i].r, e[i].maxx);
}
}
dij();
int ans = -inf;
for(int i = 1; i <= col; ++ i) ans = max(ans, dis[i]);
cout << ans;
return 0;
}