8.31 图论专项三模拟赛小记
A.虫洞,原题:bzoj 4773.负环
题意:给你一张有向图,找出点数最小的负环。
若能从题目中提取出这些信息会好做一些。
有负边权且 n 不大,适合用 floyd。需要跑的边巨多所以用倍增。
严格意义上来说我是在这道题才学会用倍增 + 矩乘优化 dijkstra or floyd 的。所以还是说一下当时的感受:
上学期初刚学倍增时一直不理解,那时对有关二进制的优化的体会非常有限。在这几天的练习中终于比较理解其思路了。在这里的倍增方式可以类比找 LCA 的思路:因为二次幂之和总能拼出任意一个数,所以从大到小枚举 2 的第 i 次幂,若跳到 2^i 后问题可以解决,则不跳(往下细找);反之则跳过去,因为要把答案拼出来。
综上,代码没什么好解释的了。但是这种倍增优化的思想是很重要的。
Code bzoj 4773
#include<bits/stdc++.h>
using namespace std;
const int N = 310;
const int inf = 0x3f3f3f3f;
int n, m;
int ans = 1;
struct M{
int a[N][N];
M()
{
for(int i = 1; i < N; i ++ )
for(int j = 1; j < N; j ++ ) a[i][j] = inf;
}
M operator *(const M &x) const{
M b;
for(int k = 1; k <= n; k ++ )
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ )
b.a[i][j] = min(b.a[i][j], a[i][k] + x.a[k][j]);
return b;
}
}f[33], x, y;
int main()
{
scanf("%d%d", &n, &m);
while(m -- )
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
f[0].a[u][v] = w;
}
for(int i = 1; i <= n; i ++ ) f[0].a[i][i] = y.a[i][i] = 0;
int t = 0;
for(int i = 1; (1 << i) <= n; i ++ )
{
t = i;
f[i] = f[i - 1] * f[i - 1];
}
for(int i = t; i >= 0; i -- )
{
x = y * f[i];
int flag = 1;
for(int j = 1; j <= n; j ++ ) if(x.a[j][j] < 0) {flag = 0; break;}
if(flag) ans += (1 << i), y = x;
}
printf("%d", (ans > n) ? 0 : ans);
return 0;
}
B.重要度,原题:P2047 [NOI2007] 社交网络
tip: syoj 上的答案是洛谷上的一半。
C.灾后重建,原题:P1772 [ZJOI2006] 物流运输
D.天天爱跑步
本文作者:Moyyer_suiy
本文链接:https://www.cnblogs.com/Moyyer-suiy/p/17677323.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步