解题报告:这题可以用spfa判断正环的做法+二分来做,我们二分他的环的平均长度,看看能不能凑成环,如果暴力去把每个字符串变成一个点,总共会有1e5的点,可以优化一下,把整个字符串变成一条边,把前两个和后两个的单词字母映射成一个点,总共26*26个点,如果朴素去做会tle,那么要加个玄学优化,如果更新次数太多的话(十几倍左右)就暂且认为他是一个环,然后stl的queue太慢了,要用数组来模拟队列。

#include<bits/stdc++.h>
using namespace std;
const   int N=100010,M=700;
int h[M],e[N],ne[N],idx;
double w[N];
bool st[M];
int cnt[M];
double dist[M];
int q[N];
int n;
void add(int a,int b,int c)
{
   
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
bool check(double mid)
{
   
    memset(st, 0, sizeof st);
    memset(cnt, 0, sizeof cnt);
    int hh = 0, tt = 0;
    for (int i = 0; i < 676; i ++ )
    {
   
        q[tt ++ ] = i;
        st[i] = true;
    }
        int count=0;
    while(hh!=tt)
    {
   
        int t=q[hh++];
        if(hh==M)   hh=0;
        st[t]=false;
        for(int i=h[t];~i;i=ne[i])
    {
   
        int j=e[i];
        if(dist[j]<dist[t]+w[i]-mid)
        {
   
            dist[j]=dist[t]+w[i]-mid;
            cnt[j] = cnt[t]+1;
            if(!st[j])
            {
   
                st[j] = true;
                q[tt++]=j;
                if(tt==M)   tt=0;
            }
            if(cnt[j]>=M)   return true;
            if(++count>=10000)  return true; // 经验上的trick
        }
        
    }
    }
    return false;
}
int main()
{
   
    while(cin>>n,n)
   {
   
       idx=0;
      memset(h,-1,sizeof h);
    for(int i=0;i<n;i++)
    {
   
        string s;
        cin >> s;
        if(s.size()>=2)
       {
    int id = (s[0]-'a')*26 + (s[1]-'a');
        int id2=(s[s.size()-2]-'a')*26 + (s[s.size()-1]-'a');
        add(id,id2,s.size());
        }
    }
        double l=0,r=1e3;
        if(!check(0))
        cout<<"No solution"<<endl;
        else
       {
    
           while(r-l>1e-4)
        {
   
            double mid=(l+r)/2;
            if(check(mid))
            l=mid;
            else
            r=mid;
        }
        printf("%.2lf\n",l);
       }
        
   }
   return 0;
}