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

Word rings

Word rings

题目链接

题目:

给定数个字符串 一个字符串的最后两个字符与另一字符串的前两个字符相同则称两个字符串能够相连
当若干个串串成一个环时 求最大的字符环的平均长度

思路:

首先 我们把每一个字符串的前两个字符以及后两个字符以哈希思想分别映射成整数 以每组字符为点 字符串的长度为边
这样 题目就变成了在图中找到一个环 使得这个环的平均边权最大

然后考虑求解平均数
设 最终的平均边权为 ave
则 有:

\[ave = \frac{\sum_{i = 1}^{k}e_i}{k} \]

移项:

\[ave \times k = \sum_{i = 1}^{k}e_i \]

即:

\[\sum_{i = 1}^{k}e_i - ave \times k = 0 \]

\[\sum_{i = 1}^{k}e_i - \sum_{i = 1}^{k}ave = 0 \]

\[\sum_{i = 1}^{k}(e_i - ave) = 0 \]

此处的\(ave\)是最优解 而范围内的其他合法解(题目允许有0.01的误差)则是将等于号改为小于等于号 这里就可以采用二分答案
我们直接二分一个平均值 判断是否满足\(\sum_{i = 1}^{k}(e_i - ave) \geq 0\)
换句话说 就是判断正环
对于正环的判断 采用 spfa_dfs 效率很高

最后注意输出要求里面 No solution. 后面这个点(不要问为什么

code:

/*
  Time: 1.30
  Worker: Blank_space
  Source: #10082. 「一本通 3.3 例 1」Word Rings
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
#define emm(x) memset(x, 0, sizeof x)
#define fil(x) fill(x, x + tot, 0)
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[B];
int n, c[D], tot, maxx, vis[700];
double dis[700], ans, eps = 1e-3;
char s[B];
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;
}
/*----------------------------------------快读*/
int max(int x, int y) {return x > y ? x : y;}
void clear() {int i = 0; emm(e); tot = 0; emm(c); maxx = 0; ans = 0;}
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; fil(dis); fil(vis);
	for(int i = 1; i <= tot; i++)
	{
		spfa(i, i, x);
		if(p) return p;
	}
	return p;
}
/*----------------------------------------函数*/
int main()
{
//	freopen("i1.in", "r", stdin);
    while(scanf("%d", &n) && n)
    {
    	clear();
    	for(int i = 1; i <= n; i++)
		{
			scanf("%s", s + 1);
			int len = strlen(s + 1); maxx = max(maxx, len);
			int x = (s[1] - 96) * 30 + s[2] - 96, y = (s[len - 1] - 96) * 30 + s[len] - 96;
			if(!c[x]) c[x] = ++tot; if(!c[y]) c[y] = ++tot;
			e[c[x]].push_back((edge){c[y], (double)len});
		}
		double l = 0, r = (double)maxx;
		while(l + eps < r)
		{
			double mid = (l + r) / 2;
			if(check(mid)) {ans = mid; l = mid;}
			else r = mid;
		}
		if(ans) printf("%.3f\n", ans);
		else puts("No solution");
	}
	return 0;
}

posted @ 2021-01-30 16:20  Blank_space  阅读(91)  评论(0编辑  收藏  举报
// // // // // // //