分析:所有的文法都能拆分成A=S1S2这种形式,设状态f[i]j]表示字符i能生成的长度为j的字典序最小字符串,那么f[i][j] = min(f[k][j'] + f[l][j-j']),但是这样会有同层转移的情况,这种情况下状态之间会产生环,我们需要把这种情况拿出来特盘一下(单独跑一遍dij).
#include <bits/stdc++.h> using namespace std; typedef pair<string,int> pii; typedef pair<int,int> pi2; vector<pi2> G[600]; int n,l,cnt; bool vis[600][25],done[600]; char str[25]; string d[600],f[600][25]; priority_queue<pii,vector<pii>,greater<pii> > q; int main() { string INF = "~~"; while(scanf("%d%d",&n,&l) && (n+l)) { for(int i = 1;i <= 600;i++) G[i].clear(); cnt = 130; for(int i = 1;i <= n;i++) { scanf("%s",str); int n = strlen(str); if(n == 2) G[str[0]].push_back(make_pair(0,0)); else if(n == 3) G[str[0]].push_back(make_pair(str[2],0)); else if(n == 4) G[str[0]].push_back(make_pair(str[2],str[3])); else { G[str[0]].push_back(make_pair(str[2],++cnt)); for(int j = 3;j < n-2;j++) { G[cnt].push_back(make_pair(str[j],cnt+1)); cnt++; } G[cnt].push_back(make_pair(str[n-2],str[n-1])); } } for(int i = 0;i <= cnt;i++) for(int j = 0;j <= l;j++) f[i][j] = INF; memset(vis,0,sizeof(vis)); //状态是否可行 for(int i = 'A';i <= 'Z';i++) // l = 0的边界转移 for(pi2 v : G[i]) if(!(v.first + v.second)) { vis[i][0] = 1; f[i][0] = ""; } vis[0][0] = 1; for(char i = 'a';i <= 'z';i++) // l = 1的边界转移 { vis[i][1] = 1; f[i][1] = i; } for(int j = 0;j <= l;j++) { while(!q.empty()) q.pop(); for(int i = 0;i <= cnt;i++) d[i] = INF; memset(done,0,sizeof(done)); for(int i = 'A';i <= cnt;i++) { for(int k = 1;k < j;k++) for(pi2 v : G[i]) { if(vis[v.first][k] & vis[v.second][j-k]) { f[i][j] = min(f[i][j],f[v.first][k] + f[v.second][j-k]); vis[i][j] |= 1; } } if(vis[i][j]) { d[i] = f[i][j]; q.push(make_pair(d[i],i)); } } while(!q.empty()) { int u = q.top().second; q.pop(); if(done[u]) continue; done[u] = true; vis[u][j] = 1; f[u][j] = d[u]; for(int i = 'A';i <= cnt;i++) if(!done[i]) for(pi2 v : G[i]) if(v.first == u || v.second == u) { if(v.first == u && vis[v.second][0]) d[i] = d[u]; if(v.second == u && vis[v.first][0]) d[i] = d[u]; if(d[i] == d[u]) q.push(make_pair(d[i],i)); } } } if(!vis['S'][l]) { cout<<'-'<<endl; continue; } else cout<<f['S'][l]<<endl; } }