您的位置:首页 > 其它

UVa1375- The Best Name for Your Baby

2015-10-20 17:17 316 查看
提示:

1. 这是一个dp题 , 不要妄想用bfs来写此题 , 样例都过不了

2. dp方程的含义: d [ i ] [ j ] , 用一个大写字母(i+'A') 扩展成长度为j的字典序最小的字符串(不含大写字母)

此处请思考些时间 , 怎么转移状态;

3. 下面是我自己的转移方法 , 与紫书上的不同 , 紫书上把边拆分成了很多块 , 但对于初学做这个题的人来说 , 把边颠过来倒过去就够呛了 , 所以我的解法在保证时间的情况下尽量去降低代码和理解的难度:

下文中所有的状态指d[i][j] , 所有的边指的是原题中形如"A=Sbs.."的文法

首先考虑转移方程:(分成同层和非同层两个部分)

对于d [ i ] [ j ] ,遍历 i 的每一条边 , 尝试通过这些边来从非同层的状态转移(有一点抽象 , 想象把一个字符串中的所有大写字母换成另一字符串 , 并拼接在一起) , 这就是我们要做的事情 ,类似于每一个大写字母贡献一个长度 , 然后小写字母呆在原来的位置,  至于非同层状态是指大写字母贡献的那个长度要严格小于 j (即是现在计算的长度)

同层dp , 就是一个dijktra 算法 , 因为在同一层中d值我们只用较小的状态去更新较大的状态 , 与dijkstra的思想不谋而合

如果能够同层dp  , i 肯定有这样一些转换边 , 转换出来的字符串都是大写字母 , 我们从中选择一个大写字母来p , 用d[p][j]来更新 d[i][j] , 当然除了p以外的所有大写字母都可以直接或间接的变成空串.

答案就是 d[ 'S'-'A' ][ l ] 

注意: 这个dp的起始需要特殊判断 , 即要知道哪些大写字母可以转化成空串 , 我用了一个bellmanFord算法 , 不知道是否有更简洁的做法呢

//
// main.cpp
// UVa1375_NEW+
//
// Created by Fuxey on 15/10/20.
// Copyright © 2015年 corn.crimsonresearch. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <list>
#include <stack>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

// d[i][j] using uppercase i+'A' to make a the minist string of length j

struct edge
{
int u , all;
string to;
edge(int u = 0,string to = ""):u(u),to(to){}
};

vector<edge> e;

bool zero[30];

inline int id(char c){ return c-'A'; }

vector<int> g[30];

int can[30][30];
string d[30][30];

int main(int argc, const char * argv[]) {

int n , l;

while(cin>>n>>l && n+l)
{
memset(zero, 0, sizeof(zero));
e.clear();
for(int i=0;i<26;i++) g[i].clear();
memset(can, 0, sizeof(can));

while(n--)
{
string op;
cin>>op;
if(op.size()==2) zero[id(op[0])] = 1;
else g[id(op[0])].push_back((int)e.size());
e.push_back(edge(id(op[0]) , op.substr(2,op.size()-2)));
e.back().all = 1;
for(int i=2;i<op.size();i++) if(islower(op[i])) { e.back().all = 0; break; }
}

bool update = true;
for(int i=1;i<=26 && update; i++)
{
update = false;
for(int j=0;j<e.size();j++) if(e[j].all && !zero[e[j].u])
{
bool ok = true;
for(int k=0;k<e[j].to.size();k++) if(!zero[id(e[j].to[k])]) { ok = false; break; }
if(ok) zero[e[j].u] = 1 , update = true;
}
}

for(int i=0;i<e.size();i++) if(e[i].all)
{
bool ok = true;
for(int j=0;j<e[i].to.size();j++) if(!zero[id(e[i].to[j])]) { ok = false; break; }
if(ok) for(int j=0;j<e[i].to.size();j++) can[id(e[i].to[j])][e[i].u] = 1;
else
{
int cnt = 0 , wh = 0;
for(int j=0;j<e[i].to.size();j++) if(!zero[id(e[i].to[j])]) cnt++ , wh = id(e[i].to[j]);
if(cnt==1) can[wh][e[i].u] = 1;
}
}

for(int i=0;i<26;i++) for(int j=0;j<=l;j++) d[i][j] = "{";

for(int i=0;i<26;i++) if(zero[i]) d[i][0] = "";

string now[30]; int book[30];
for(int i=1;i<=l;i++)
{
for(int j=0;j<26;j++) for(int k=0;k<g[j].size();k++) // I am calculating d[j][i]
{
edge& enow = e[g[j][k]];
int cnt = 0;
for(int ll = 0;ll<=i;ll++) now[ll] = "{"; now[0]="";
for(int ll = 0;ll<enow.to.size();ll++)
{
if(islower(enow.to[ll]))
{
cnt++;
for(int q=i;q>=cnt;q--) if(now[q-1]!="{") now[q] = now[q-1]+enow.to[ll]; else now[q] = "{";
now[cnt-1] = "{"; // it is impossible
}
else
{
for(int q = i;q>=cnt;q--)
{
string Min = "{"; // each letter must do something to the answer , or it can not be successful
for(int p = min(q-cnt,i-1);p>=0;p--)if(d[id(enow.to[ll])][p]!="{")
Min = min(Min , now[q-p]+d[id(enow.to[ll])][p]);
now[q] = Min;
}
}
}
d[j][i] = min(d[j][i] , now[i]);
}

// samelevel kind
memset(book, 0, sizeof(book));
for(int j=1;j<=26;j++)
{
string Min = "{" ; int x = 0;
for(int k=0;k<26;k++) if(!book[k] && d[k][i]<=Min) Min = d[k][i] , x = k;
book[x] = 1;

for(int k=0;k<26;k++) if(can[x][k]) d[k][i] = min(d[k][i] , Min);
}
}
if(d[id('S')][l]=="{") cout<<"-\n";
else cout<<d[id('S')][l]<<endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  uva dp