信息学奥赛一本通 1504:【例 1】Word Rings | 洛谷 SP2885 WORDRING - Word Rings

【题目链接】

ybt 1504:【例 1】Word Rings
洛谷 SP2885 WORDRING - Word Rings

【题目考点】

1. 图论:SPFA_DFS 判断负环

SPFA_DFS算法

Bellman-Ford算法栈优化,也称SPFA_DFS算法。

主要用于寻找图中是否存在负环或正环。

以判断负环为例:

  1. 将dis数组每个元素初值设为0
  2. 尝试从每个顶点出发调用SPFA_DFS算法。如果访问到还在搜索过程中(在栈内)的顶点,则找到负环。
    每次调用可以判断出该顶点所在的环是否是负权环。
2. 二分答案

【解题思路】

作为字符串前后端的两个字符是顶点(例单词ababc,开端ab是一个顶点,末端bc是一个顶点),每个单词是一条连接前后端两个顶点的有向边,边的权值为单词的长度(字符数)。

每读入一个单词,取出该单词的前两个字符构成的字符串,单词后两个字符构成的字符串,称为端点字符串。将端点字符串映射到表示顶点编号的整数。

设map,键位端点字符串,值为该字符串对应的顶点编号。设总顶点数量n初值为0。

每取到一个不存在的新的端点字符串,就将n增加1后n的值作为该字符串对应的顶点编号。

将端点字符串映射到整数的过程也可以设哈希函数完成。

设端点字符串的第一个字符为变量x,第二个字符为变量y,由于所有的字符都是小写的,那么将这两个字符看做一个26进制数字,哈希值为该数字的数值。哈希函数为(x-'a')*26+y-'a',这样就可以根据两个字符得到从0开始的顶点编号。

根据输入的字符串建图。

该题求图中平均路径长度最大的环。平均路径长度是环上路径总长度除以环上边数的商。

给定一个图,一定存在平均路径长度最大的环,设该环的平均路径长度为ave。

设该环上的边的长度(权值)分别为 w 1 , w 2 , . . . , w m w_1, w_2, ..., w_m w1,w2,...,wm

则 ( ∑ i = 1 m w i ) / m = a v e (\sum_{i=1}^mw_i)/m = ave (∑i=1mwi)/m=ave
∑ i = 1 m w i = a v e ⋅ m \sum_{i=1}^mw_i = ave\cdot m ∑i=1mwi=ave⋅m
w 1 − a v e + w 2 − a v e + . . . + w m − a v e = 0 w_1-ave+w_2-ave+...+w_m-ave = 0 w1−ave+w2−ave+...+wm−ave=0

即 ∑ i = 1 m ( w i − a v e ) = 0 \sum_{i=1}^m(w_i-ave) = 0 ∑i=1m(wi−ave)=0

给定平均路径长度 x x x,显然:

如果 x < a v e x<ave x<ave,则 ∑ i = 1 m ( w i − x ) > 0 \sum_{i=1}^m(w_i-x) > 0 ∑i=1m(wi−x)>0。

如果 x ≥ a v e x\ge ave x≥ave,则 ∑ i = 1 m ( w i − x ) ≤ 0 \sum_{i=1}^m(w_i-x) \le 0 ∑i=1m(wi−x)≤0。

如果将图中每条边的权值都减去x,而后只要图中存在正权环,那么一定存在一个环满足 ∑ i = 1 m ( w i − x ) > 0 \sum_{i=1}^m(w_i-x) > 0 ∑i=1m(wi−x)>0。由于ave是最大的平均长度最大的环的平均长度,因此当 x ≥ a v e x\ge ave x≥ave时,将图中每条边的权值减少x后,一定就不存在正权环了。

将 x < a v e x<ave x<ave认为是满足条件, x ≥ a v e x\ge ave x≥ave认为是不满足条件,只需要求 x x x满足条件的最大值。由于平均值x是实数, x < a v e x<ave x<ave前提下x的最大值会无限接近ave,可以认为x满足条件的最大值等于ave。

可以通过二分答案方法解决该问题:

  • 答案变量:环的平均路径长度x。
  • 最值:最大值
  • 满足条件:将图中每条边的权值都减去x后,图中存在正权环。

注意:此处不能 求平均路径长度x满足图中存在负权环情况下 x x x的最小值。

因为ave是平均路径长度最大的环的平均路径长度, x x x取某个值后,图中每条边的边权都减少x,即便图中存在负权环,可能是平均路径长度较小的一个环变成了负权环,而平均路径长度最大的环的边权加和还满足 ∑ i = 1 m ( w i − x ) > 0 \sum_{i=1}^m(w_i-x)>0 ∑i=1m(wi−x)>0,并非满足 x > a v e x>ave x>ave。

先判断,当环的平均路径长度x为0时,原图每条边的权值不变,判断是否存在正权环。如果不存在,则输出 No solution。

而后在实数域进行二分答案:

答案变量环的平均路径长度 x x x:最小为 0 0 0,最大为总边权最大值 1000 ∗ 1 0 5 = 1 0 8 1000*10^5=10^8 1000∗105=108。找满足条件的最大值。使用SPFA_DFS算法判断图中是否存在正权环。

【注意】该题有多组数据,注意要清空变量。

【题解代码】

解法1:二分答案,SPFA_DFS判断正环

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define N 100005
struct Edge
{
	int v;
	double w;
};
int sn, n;
vector<Edge> edge[N];
map<string, int> num;//将长为2的字符串转为数字编号
bool inStk[N];
double dis[N];
bool spfa_dfs(int u, double ave)//每条边权值减去ave,判断是否存在正环 
{
	inStk[u] = true;
	for(Edge e : edge[u])
	{
		int v = e.v;
		double w = e.w-ave; 
		if(dis[v] <= dis[u]+w)//等于时也松弛,可以找到0权环
		{
			dis[v] = dis[u]+w;
			if(inStk[v] || spfa_dfs(v, ave))
				return true;
		}
	}
	inStk[u] = false;
	return false;
}
bool check(double ave)//在每条边边权都减去ave后,是否存在正权环 
{
	memset(dis, 0, sizeof(dis));
	memset(inStk, 0, sizeof(inStk));
	for(int i = 1; i <= n; ++i)	if(spfa_dfs(i, ave))
		return true;
	return false;
} 
int main()
{
	string s;
	while(cin >> sn && sn != 0)
	{
		for(int i = 0; i < N; ++i)
			edge[i].clear();
		num.clear();
		n = 0;
		for(int i = 1; i <= sn; ++i)
		{
			cin >> s;
			if(s.length() < 2)
				continue;
			string front = s.substr(0, 2), back = s.substr(s.length()-2);
			if(num.find(front) == num.end())
				num[front] = ++n;
			if(num.find(back) == num.end())
				num[back] = ++n;
			edge[num[front]].push_back(Edge{num[back], (double)s.length()});		
		}
		if(!check(0))//ave为0,判断原图是否有正环 
		{
			cout << "No solution." << '\n';
			continue;
		}
		double l = 0, r = 1e8;
		while(r-l >= 1e-8)
		{
			double mid = (l+r)/2;
			if(check(mid))
				l = mid;
			else
				r = mid;
		}
		cout << fixed << setprecision(2) << l << '\n';
	}
	return 0;
}
相关推荐
深邃-6 分钟前
【数据结构与算法】-二叉树(2):实现顺序结构二叉树(堆的实现),向上调整算法,向下调整算法,堆排序,TOP-K问题
数据结构·算法·二叉树·排序算法·堆排序··top-k
We་ct3 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·javascript·算法·leetcode·typescript
王老师青少年编程7 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮8 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说8 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
wuweijianlove8 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法
leoufung9 小时前
LeetCode 149: Max Points on a Line - 解题思路详解
算法·leetcode·职场和发展
样例过了就是过了9 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
HXDGCL9 小时前
矩形环形导轨:自动化循环线的核心运动单元解析
运维·算法·自动化
谭欣辰9 小时前
C++ 排列组合完整指南
开发语言·c++·算法