Description
Bsny从字典挑出N个单词,并设计了接龙游戏,只要一个单词的最后两个字母和另一个单词的前两个字母相同,那么这两个单词就可以有序的连接起来。
Bsny想要知道在所给的所有单词中能否按照上述方式接龙组成一个单词环(可能是多个),若能,求所有环的环中单词平均长度最大值。
Solution
看到平均和最值,差不多就是二分答案,
把单词看成边,两个字母看成点,先连上边,(注意,是单向的)
二分一个答案,把每一条边都减掉二分出的答案,全局跑一遍SPFA,看看有没有正环,有就增加,没有就减小;
显然,如果有正环,SPFA就会不停的跑下去,判断有没有正环,就设一个阈值,如果SPFA跑的次数超过了,就说明有正环,
复杂度:O(log(109)∗k)(k为设的阈值)
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
using namespace std;
typedef double db;
const int N=30500;
const db M=1e-6;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,TI;
int B[N*4][2],A[N],B0=1;
db ans;
int z[N],d[10*N];
db JA;
db d1[N];
int b1[2700][2700];
void link(int q,int w){B[++B0][0]=A[q];A[q]=B0,B[B0][1]=w;}
bool SPFA()
{
int s=1,t=m,q;
int CT=0;
TI+=2;
fo(i,1,m)d1[d[i]]=0,z[d[i]]=TI-1;
while(s<=t)
{
CT++;
if(CT>4*n)return 1;
q=d[s++];
efo(i,q)if(d1[q]+b1[q][B[i][1]]-JA+M>d1[B[i][1]])
{
d1[B[i][1]]=d1[q]+b1[q][B[i][1]]-JA;
if(z[B[i][1]]<TI-1)z[B[i][1]]=TI-1,d[++t]=B[i][1];
if(z[B[i][1]]==TI-1)z[B[i][1]]=TI,d[++t]=B[i][1];
}
z[q]=TI-2;
}
return 0;
}
int main()
{
int q,w,e;
scanf("%d",&n);
fo(i,1,n)
{
char ch=' ',ch1,ch2;
while(ch<'a'||ch>'z')ch=getchar();
ch1=getchar();
q=(ch-96)*100+ch1-96;ch2=ch;
e=1;
for(;ch>='a'&&ch<='z';ch=getchar(),e++)ch2=ch1,ch1=ch;
w=(ch2-96)*100+ch1-96;
if(!b1[q][w])b1[q][w]=e,link(q,w);
b1[q][w]=max(b1[q][w],e);
}
fo(i,1,26)fo(j,1,26)if(A[i*100+j])d[++m]=i*100+j;
db l=0,r=1e9;
while(r-l>2e-3)
{
db t=(l+r)/2;JA=t;
if(SPFA())l=t;
else r=t;
}
printf("%.4lf\n",r);
return 0;
}