2021牛客暑期多校训练营7 J. xay loves Floyd 预处理最短路+bitset
Posted kaka0010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营7 J. xay loves Floyd 预处理最短路+bitset相关的知识,希望对你有一定的参考价值。
原题链接:https://ac.nowcoder.com/acm/contest/11258/J
题意
正确的弗洛伊德算法是依照枚举k, i, j的顺序,k是转移的中间点,i是出发点,j是到达点。现在按照i,j,k的枚举顺序,问有多少点对之间的最短路仍然是正确的。
分析
我们分两种情况来考虑
- u本来就不能到达v,u和v是同一个点。
- u通过最短路径dis[u,k]到达k,再通过最短路经dis[k,v]到达v,且k是u,v最短路径上的必经点
对于第一种情况我们直接统计就可以了,对于第二种,我们需要预处理出所有点作为出发点的最短路。然后再按照题目中的枚举顺序去枚举。比如我们枚举从u出发到所有点的距离,存在dis[v]中,那么我们需要同时满足存在点p,dis[u][p]和dis[p][v]都是最短路,且p位于u,v的最短路径上。如果直接暴力算是O(N^3)的,我们可以把所有经过的点用bitset压位处理。还有一处重要的剪枝,就是只有最短路才能更新最短路,因此我们将从当前u出发且满足最短路的边拎出来,用拓扑乱搞更新一下就可以。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ul;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const ll mod = 1e9 + 7;
const double eps = 1e-8;
#define lowbit(i) (i & -i)
#define Debug(x) cout << (x) << endl
#define fi first
#define se second
#define mem memset
#define endl '\\n'
int can[2005][2005];
int dis[2005], vis[2005], n, m, in[2005];
vector<int> G[2005];
vector<PII> g[2005];
bitset<2005> mk[2005], f[2005], fT[2005];
struct Edge {int u, v, w;} e[5005];
struct node {
int d, now;
bool operator < (const node &rhs) const {
return d > rhs.d;
}
};
void dij(int x) {
memset(vis, 0, sizeof vis);
memset(dis, 0x3f, sizeof dis);
dis[x] = 0;
priority_queue<node> que;
que.push({0, x});
while (que.size()) {
int now = que.top().now;
que.pop();
if (vis[now]) continue;
vis[now] = 1;
for (auto it : g[now]) {
int v = it.fi;
int w = it.se;
if (dis[v] > dis[now] + w) {
dis[v] = dis[now] + w;
if (!vis[v]) {
que.push({dis[v], v});
}
}
}
}
for (int i = 1; i <= n; i++) can[x][i] = dis[i];
}
inline void solve() {
cin >> n >> m;
for (int i = 1; i <= n; i++) f[i][i] = fT[i][i] = 1;
for (int i = 1; i <= m; i++) {
int u, v, w; cin >> u >> v >> w;
e[i] = {u, v, w};
g[u].push_back({v, w});
}
for (int i = 1; i <= n; i++) dij(i);
for (int i = 1; i <= m; i++) {
if (can[e[i].u][e[i].v] == e[i].w) f[e[i].u][e[i].v] = fT[e[i].v][e[i].u] = 1;
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
in[j] = 0;
mk[j].reset();
G[j].clear();
ans += (can[i][j] == inf);
}
queue<int> q;
for (int j = 1; j <= m; j++) {
if (can[i][e[j].u] + e[j].w == can[i][e[j].v]) {
G[e[j].u].push_back(e[j].v);
in[e[j].v]++;
}
}
q.push(i);
while (q.size()) {
int now = q.front();
q.pop();
mk[now][now] = 1;
for (auto v : G[now]) {
mk[v] |= mk[now];
if (--in[v] == 0) q.push(v);
}
}
for (int j = 1; j <= n; j++) {
if ((f[i] & mk[j] & fT[j]).count()) f[i][j] = fT[j][i] = 1;
}
}
for (int i = 1; i <= n; i++) ans += f[i].count();
cout << ans << endl;
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}
以上是关于2021牛客暑期多校训练营7 J. xay loves Floyd 预处理最短路+bitset的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客暑期多校训练营7 F.xay loves trees(主席树+树上尺取)
2021牛客暑期多校训练营7xay loves trees(dfs序,维护根出发的链)