原题链接

考察:01分数规划+SPFA判环

思路:

        和之前的最小环没什么区别,本题最难在建边.看题目很想当然的是二重for循环字符串建边,但是明显会TLE并且MLE,

        考虑换一个思路, ababc + bckjaca -> aba bc kjaca  只考虑前面两个与结尾两个,就转化为 ab-> bc->ca即将字符串化为边.这样点最多26*26个,边最多10个.

        最后就是SPFA+玄学优化.

       注意n是边的数量.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <queue>
 4 #include <map>
 5 using namespace std;
 6 const double eps = 1e-6;
 7 const int N = 680,M = 100010,S = 1010;
 8 int n,id,idx,h[N],cnt[N];
 9 map<int,int> mp;
10 bool st[N];
11 double dist[N];
12 char s[S];
13 struct Road{
14     int fr,to,ne,w;
15 }road[M];
16 void add(int a,int b,int w)
17 {
18     road[idx].w = w,road[idx].fr = a,road[idx].to = b,road[idx].ne =h[a],h[a] = idx++;
19 }
20 int get(int x)
21 {
22     if(!mp.count(x)) mp[x] = ++id;
23     return mp[x];
24 }
25 bool check(double mid)
26 {
27     queue<int> q;
28     int count = 0;
29     for(int i=1;i<=id;i++) dist[i] = 0,cnt[i] = 0,q.push(i),st[i] = 1;
30     while(q.size())
31     {
32         int u = q.front();
33         q.pop();
34         st[u] = 0;
35         for(int i=h[u];~i;i=road[i].ne)
36         {
37             int v = road[i].to;
38             if(dist[v]<dist[u]+road[i].w - mid)
39             {
40                 dist[v] = dist[u]+road[i].w - mid;
41                 cnt[v] = cnt[u]+1,count++;
42                 if(count>=4*id) return 1;
43                 if(cnt[v]>=id) return 1;
44                 if(!st[v]) q.push(v),st[v] = 1;
45             }
46         }
47     }
48     return 0;
49 }
50 int main()
51 {
52     while(scanf("%d",&n)!=EOF&&n)
53     {
54         idx = 0;
55         id = 0; mp.clear();
56         for(int i=1;i<=N-4;i++) h[i] = -1;
57         for(int i=1;i<=n;i++)
58         {
59             scanf("%s",s);
60             int len = strlen(s);
61             int a = (s[0]-'a'+1)*26+(s[1]-'a'+1);
62             int b = (s[len-2]-'a'+1)*26+(s[len-1]-'a'+1);
63             int fr = get(a); int to = get(b);
64             add(fr,to,len);
65         }
66         double l = 0,r = 1010;
67         while(r-l>=eps)
68         {
69             double mid = (l+r)/2;
70             if(check(mid)) l = mid;
71             else r = mid;
72         }
73         if(r>=eps) printf("%.2lf\n",r);
74         else puts("No solution");
75     }
76     return 0;
77 }