Uva-1375 The Best Name for Your Baby(复杂DP)

185 篇文章 0 订阅
116 篇文章 0 订阅

分析:所有的文法都能拆分成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;
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值