Richard_H @ 2022-10-11 17:36:20
这个题,因为强连通分量肯定是一个半连通图,所以可以把一坨点缩成一个点,点权为这一坨点的个数,然后就建一个新的图出来,用 set 避免重边,然后搞一个超级源点跑 spfa 。结果只能过 5 个点,卡在了第 6 个点,把 spfa 那部分改成拓扑之后就又对了,这是为什么?
下面是我提交的过了 5 个点的代码 ↓ ↓ ↓
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n, m, x, tim = 0, idx = 0, dis[N], clr[N], dfn[N], dist[N], low[N], cnt[N], u, v, ans = 0, ans_num;
bool vis[N], st[N];
stack<int> s;
queue<int> q;
vector<int> lnk[N];
set< pair<int, int> > exl[N];
void tarjan(int x) {
vis[x] = true;
s.push(x);
dfn[x] = low[x] = ++tim;
for(auto item : lnk[x]) {
if(!dfn[item]) {
tarjan(item);
low[x] = min(low[x], low[item]);
} else if(vis[item]) {
low[x] = min(low[x], dfn[item]);
}
}
if(dfn[x] == low[x]) {
int op;
idx ++;
do{
op = s.top();
s.pop();
clr[op] = idx;
dis[idx] ++;
vis[op] = false;
} while(op != x);
}
}
void spfa(){
memset(dist, -1, sizeof dist);
q.push(0);
dist[0] = 0;
cnt[0] = 1;
while(!q.empty()) {
int op = q.front();
q.pop();
st[op] = false;
for(auto item : exl[op]) {
if(dist[item.first] < dist[op] + item.second) {
dist[item.first] = dist[op] + item.second;
cnt[item.first] = cnt[op];
if(!st[item.first]) {
q.push(item.first);
st[item.first] = true;
}
} else if(dist[item.first] == dist[op] + item.second) cnt[item.first] = (cnt[item.first] + cnt[op]) % x;
}
}
}
int main(){
scanf("%d%d%d", &n, &m, &x);
for(int i = 1; i <= m; i ++ ) {
scanf("%d%d", &u, &v);
lnk[u].push_back(v);
}
for(int i = 1; i <= n; i ++ ) {
if(!dfn[i]) {
tarjan(i);
}
}
// printf("%d\n", idx);
// for(int i = 1; i <= n; i ++ ) {
// printf("%d %d\n", i, clr[i]);
// }
for(int i = 1; i <= n; i ++ ) {
for(auto item : lnk[i]) {
if(clr[i] != clr[item]) {
exl[clr[i]].insert({clr[item], dis[clr[item]]});
// printf("%d %d %d\n", clr[i], clr[item], dis[clr[item]]);
}
}
}
for(int i = 1; i <= idx; i ++ ) {
exl[0].insert({i, dis[i]});
// printf("0 %d %d\n", i, dis[i]);
}
spfa();
for(int i = 1; i <= idx; i ++ ) {
// printf("%d %d %d\n", i, dist[i], cnt[i]);
if(ans < dist[i]) {
ans = dist[i];
ans_num = cnt[i];
} else if(ans == dist[i]) ans_num = (ans_num + cnt[i]) % x;
}
printf("%d\n%d", ans, ans_num);
return 0;
}
by so_find_skind @ 2022-10-11 17:59:44
这道题估计是spfa的三转路克星