[SPOJ]2885 loj10082 WORDRING - Word Rings

链接:

loj:https://loj.ac/problem/10082

luogu:https://www.luogu.com.cn/problem/SP2885

SPOJ:https://www.spoj.com/problems/WORDRING/

对于每个字符串的首尾两个长度为\(2\)的子串,哈希之后连一条权为当前字符串的长度的有向边

然后题目只需要找到边权平均值最大的正环

设正环由\(k\)条边组成,分别标号为\(1,2,…,k\),第\(i\)条边的长度为\(d_i\)

则平均值\(a=\dfrac{ \sum \limits^{k}_{i=1} d_i } {k}\)

然后\(\sum\limits^{k}_{i=1} (d_i - a) = 0\)

做上式大于\(0\),则说明有更优解

于是考虑二分答案即可做出

代码:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(register int i=a;i<=b;++i)
inline int read()
{
    bool f=0;int x=0;char ch;
    do{ch=getchar();f|=(ch=='-');}while(!isdigit(ch));
    do{x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}while(isdigit(ch));
    return f?-x:x;
}
inline void write(int x)
{
    if(x<0)x=-x,putchar('-');
    if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writesp(int x)
{
	write(x);putchar(' ');
}
inline void writeln(int x)
{
	write(x);puts("");
}
const int maxn=1e6+5; 
int head[maxn],nxt[maxn],w[maxn],to[maxn],vis[maxn],tot;
double dis[maxn];
void insert(int u,int v,int val)
{
    nxt[++tot]=head[u];
    head[u]=tot;
    w[tot]=val;
    to[tot]=v;
}
int spfa(double t,int u)
{
	vis[u]=1;
	for(int i=head[u];i;i=nxt[i])
	{
		int v=to[i],val=w[i];
		if(dis[v]<dis[u]+val-t)
		{
			dis[v]=dis[u]+val-t;
			if(vis[v]||spfa(t,v))
				return 1;
		}
	}
	vis[u]=0;
	return 0;
}
int check(double mi)
{
	memset(dis,0,sizeof(dis));
	memset(vis,0,sizeof(vis));
	rep(i,1,1e5)if(spfa(mi,i))return 1;
	return 0;
}
int main()
{
	while(1)
	{
		int n=read(),sum=0;tot=0;
		memset(to,0,sizeof(to));memset(w,0,sizeof(w));memset(nxt,0,sizeof(nxt));memset(head,0,sizeof(head));
		if(!n)break;
		rep(i,1,n)
		{
			string s;cin>>s;
			int len=s.size(),a=(s[0]-96)*100+(s[1]-96),b=(s[len-2]-96)*100+(s[len-1]-96);
			insert(a,b,len);
			sum+=len;
		}
		double l=0,r=sum,mid;
		while(l+1e-2<r)
		{
			mid=(l+r)/2;
			if(check(mid)) l=mid;
			else r=mid;
		}
		if(l==0)
			puts("No solution");
		else
			printf("%.2lf\n",l);
	}
	return 0;
}
上一篇:LeetCode 96 不同的二叉搜索树I


下一篇:视频流操作记录