UVa1375- The Best Name for Your Baby

提示:

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;
}


你可能感兴趣的:(dp,uva)