// // // // // // // // // // // // // //

关于 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判负环或者是正环

感觉优化似乎不是很多的样子...

posted @ 2021-01-30 20:13  Blank_space  阅读(72)  评论(2编辑  收藏  举报
// // // // // // //