SP2885 WORDRING - Word Rings

这道题是能够一眼看出思路的(然而我是错的),就是想求出所有的环,然后在所有环中比较出环串的平均长度最长的那一个,然后就完了

但是很明显这个东西基本无法实现(或者是我单纯太弱),因为无论我们想求平均长度最长,我们肯定希望跑最长路,刚好边权为字符串长度,那么跑进去正环之后就跑不出来了,所以这个想法换掉

那么继续想,我们无法枚举环来求出答案,我们就试着枚举答案,然后求出是否有满足答案的环就可以了

若我们此时枚举的答案为\(ans\),有\(k\)个字符串,那么就有

\(ans * k = len1 + len2 + len3 + ... + lenk\)

那道这个式子之后,我们对它进行移项

\(0=len1-ans+len2-ans+len3-ans+...+lenk-ans\)

那么对于满足以下式子,也可以判断是正环

\(0 \leq len1-ans+len2-ans+len3-ans+...+lenk-ans\)

那么对于这个\(ans\)\(ans\)越大,那么存在正环的概率也就越小,当\(ans\)越小时,\(ans\)大的情况肯定也会包含在里面,这就保证了单调性,可以使用二分答案来做

至于以上的最长路,应该可以使用Dijkstra判断正环,但是我还是喜欢用SPFA,因为可以判负环,而且大部分时候快一些(什么鬼才逻辑)

这里就直接上代码吧:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+51;
int n;
string s[MAXN];
struct node {
	int net,to,w;
} e[MAXN];
int head[MAXN],tot;
void add(int x,int y,double z) {
	e[++tot].net=head[x];
	e[tot].to=y;
	e[tot].w=z;
	head[x]=tot;
} 
int len[MAXN];
bool v[MAXN];
double d[MAXN];
bool dfs(int x,double k) {
	v[x]=true;
	for(register int i=head[x]; i; i=e[i].net) {
		int y=e[i].to;
		double z=e[i].w;
		if(d[y]<d[x]+z-k) {
			d[y]=d[x]+z-k; //不能理解这个式子的参考上面的解题思路 
			if(v[y]==true||dfs(y,k)==true) return true; 
			//如果当前点走过说明有正环 
		}
	}
	return v[x]=false; //记得回溯 
}
int main() {
	while(scanf("%d",&n)) {
		if(n==0) return 0;  //结束程序 
		memset(head,0,sizeof head);
		tot=0; //记得清空 
		double l=0.0,r=1e8; //二分答案的范围,可以写大一点 
		for(register int i=1; i<=n; i++) {
			cin>>s[i];
			len[i]=s[i].length();
		} //输入,记录长度,每次调用函数会慢一点 
		for(register int i=1; i<=n; i++) {
			for(register int j=1; j<=n; j++) {
				if(s[i][len[i]-1]==s[j][1]&&s[i][len[i]-2]==s[j][0]) {
					add(i,j,len[i]); //枚举每两个字符串,如果可以相连就建边,边权就为字符串长度 
				}
			}
		}
		bool ok=false; //记录是否有答案 
		while(r-l>0.001) { //实数域的二分,我的太丑啦~~ 
			double mid=(l+r)/2;
			bool op=0; //是否更新l和r 
			memset(v,false,sizeof v);
			memset(d,0,sizeof d); //清空数组 
			for(register int i=1; i<=n; i++) {
				if(dfs(i,mid)==true) { //如果有正环,说明有答案 
					ok=true;
					op=1;
					l=mid;
					break;
				}
			}
			if(!op)r=mid; //搜不出来说明r太大了 
		}
		if(ok==false) puts("No solution");
		else printf("%.2lf\n",l*1.0);
	}
	return 0;
}
posted @ 2020-07-23 20:30  Poetic_Rain  阅读(78)  评论(1编辑  收藏