关于 SPFA
SPFA 及其优化
1. Word Rings
详见题解:Word Rings
2. 双调路径
详见题解:双调路径
3. 最小圈
/*
Time: 1.30
Worker: Blank_space
Source: #10084. 「一本通 3.3 练习 1」最小圈
二分答案 找负环
*/
/*--------------------------------------------*/
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define emm(x) memset(x, 0, sizeof x)
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
struct edge {int v; double w;};
vector <edge> e[3010];
int n, m, vis[3010];
double dis[3010], ans, minv = INF, maxv = -INF;
bool p;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void spfa(int u, int tp, double x)
{
if(p) return ;
vis[u] = tp;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i].v; double w = (double)e[u][i].w - x;
if(dis[v] <= dis[u] + w) continue;
dis[v] = dis[u] + w;
if(!vis[v]) spfa(v, tp, x);
if(p) return ;
else if(vis[v] == tp) {p = 1; return ;}
}
vis[u] = 0;
}
bool check(double x)
{
p = 0; emm(dis); emm(vis);
for(int i = 1; i <= n; i++)
{
spfa(i, i, x);
if(p) return p;
}
return p;
}
/*----------------------------------------函数*/
int main()
{
n = read(); m = read();
for(int i = 1; i <= m; i++)
{
int x = read(), y = read();
double z = 0;
scanf("%lf", &z);
minv = min((double)minv, (double)z); maxv = max((double)maxv, (double)z);
e[x].push_back((edge){y, z});
}
double l = minv, r = maxv, eps = 1e-9;
while(l + eps < r)
{
double mid = (l + r) / 2;
if(check(mid)) ans = mid, r = mid;
else l = mid;
}
printf("%.8f", ans);
return 0;
}
4. 虫洞
/*
Time: 1.30
Worker: Blank_space
Source: #10085. 「一本通 3.3 练习 2」虫洞 Wormholes
道路存正边 虫洞存负边 判负环
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
#define emm(x) memset(x, 0, sizeof x)
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
struct edge {int v, w;};
vector <edge> e[510];
int T, n, m1, m2, vis[510], dis[510];
bool p;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void spfa(int u, int tp)
{
if(p) return ;
vis[u] = tp;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i].v, w = e[u][i].w;
if(dis[v] <= dis[u] + w) continue;
dis[v] = dis[u] + w;
if(!vis[v]) spfa(v, tp);
if(p) return ;
else if(vis[v] == tp) {p = 1; return ;}
}
vis[u] = 0;
}
void work()
{
n = read(); m1 = read(); m2 = read();
emm(vis); emm(dis); emm(e); p = 0;
for(int i = 1; i <= m1; i++)
{
int x = read(), y = read(), z = read();
e[x].push_back((edge){y, z}); e[y].push_back((edge){x, z});
}
for(int i = 1; i <= m2; i++)
{
int x = read(), y = read(), z = read();
e[x].push_back((edge){y, -z});
}
for(int i = 1; i <= n; i++)
{
spfa(i, i);
if(p) {puts("YES"); return ;}
}
puts("NO");
}
/*----------------------------------------函数*/
int main()
{
T = read();
while(T--) work();
return 0;
}
5. Easy SSSP
/*
Time: 1.30
Worker: Blank_space
Source: #10086. 「一本通 3.3 练习 3」Easy SSSP
可能有负环的最短路 分开写
spfa dfs bfs 写两个
时间应该是够得
注意输出
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#define emm(x) memset(x, 0, sizeof x)
#define emmm(x) memset(x, 0x3f, sizeof x)
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
struct edge {int v, w;};
vector <edge> e[1010];
int n, m, s, vis1[1010], dis1[1010], dis2[1010];
bool p, vis2[1010];
queue <int> q;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void spfa(int u, int tp)
{
if(p) return ;
vis1[u] = tp;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i].v, w = e[u][i].w;
if(dis1[v] <= dis1[u] + w) continue;
dis1[v] = dis1[u] + w;
if(!vis1[v]) spfa(v, tp);
if(p) return ;
else if(vis1[v] == tp) {p = 1; return ;}
}
vis1[u] = 0;
}
/*----------------------------------------函数*/
int main()
{
n = read(); m = read(); s = read();
for(int i = 1; i <= m; i++)
{
int x = read(), y = read(), z = read();
e[x].push_back((edge){y, z});
}
for(int i = 1; i <= n; i++)
{
spfa(i, i);
if(p) {puts("-1"); return 0;}
}
emmm(dis2); q.push(s); dis2[s] = 0;
while(!q.empty())
{
int u = q.front(); q.pop(); vis2[u] = 0;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i].v, w = e[u][i].w;
if(dis2[v] > dis2[u] + w)
{
dis2[v] = dis2[u] + w;
if(!vis2[v]) vis2[v] = 1, q.push(v);
}
}
}
for(int i = 1; i <= n; i++)
if(dis2[i] == INF) puts("NoPath");
else printf("%d\n", dis2[i]);
return 0;
}
五个题目大同小异
都是深搜spfa判负环或者是正环
感觉优化似乎不是很多的样子...