pro:开始有一个字母虫,然后字母虫在每一天可以选择自己身上的部分字母变换,变换规则形如A->BC。 现状给定最终字母虫的字符串,求最少用了多少天。
如有规则A->BC,B->AC,C->AB;则ACAB可以见过三天(A-BC-ACC-ACAC)或者两天(A-BC-ACAB)得来。 规则不超过80,字符串长度不超过50;
sol:dp[i][j][p]表示,最开始只有字母p,变换到[i,j]区间的最小天数。
显然初始:dp[i][i][x]=c[i]==x?0:inf;
其他: dp[i][j][x]=min(dp[i][k][p],dp[k+1][j][q]+1); 当且当存在规则x->pq;
经验:在倒推比较难的情况下,我们表示的状态可以是最初状态。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=52; char c[maxn],s[maxn*2][5]; int dp[maxn][maxn][maxn]; vector<int>A[20],B[20]; int main() { int N,L; while(~scanf("%d",&N)){ if(!N) break; rep(i,0,19) A[i].clear(),B[i].clear(); rep(i,1,N){ scanf("%s",s[i]); A[s[i][0]-'A'].push_back(s[i][1]-'A'); B[s[i][0]-'A'].push_back(s[i][2]-'A'); } scanf("%s",c+1); L=strlen(c+1); rep(i,1,L) rep(j,i,L) rep(k,0,19) dp[i][j][k]=L+1; rep(i,1,L) dp[i][i][c[i]-'A']=0; rep(i,1,L) { rep(l,1,L-i){ int r=l+i; rep(p,0,19){ rep(k,l,r-1){ for(int t=0;t<A[p].size();t++){ dp[l][r][p]=min(dp[l][r][p],max(dp[l][k][A[p][t]],dp[k+1][r][B[p][t]])+1); } } } } } int ans=L+1; rep(i,0,19) if(dp[1][L][i]!=-1) ans=min(ans,dp[1][L][i]); if(ans==L+1) ans=-1; printf("%d ",ans); } return 0; }