100道动态规划——35 CSUOJ 1846 Assembly Line 区间DP,增加状态

Description

The last worker in a production line at the factory of Automated Composed Machinery is worried. She knows that her job hangs in the balance unless her productivity increases. Her work consists of assembling a set of pieces in a given sequence, but the time spent on assembling pieces a and b and then c may not the same as that on assembling pieces b and c, and then assembling a with the resulting component. Only two consecutive pieces may be assembled at a time, and once they are assembled they behave as another piece in terms of the time needed for further assembly.

  In order to aid her, you need to find the optimal way to assemble all components. The input to your program will be a set of symbols representing (types of) pieces, and a so-called assembly table representing the time it takes to assemble them, as well as the type of the resulting component. For instance, we may have two symbols {a, b} and the following table:

     
  a b
a 3-b 5-b
b 6-a 2-b

  This means, for example, that two pieces of type a and a may assembled in 3 minutes, and the result is a component of type b, in that the time required to assemble it again with another piece of, say, type a is 6 minutes, and so on. Note that the table is not symmetric, i.e. assembling b and a may be more time-consuming than a and b.

  For a sequence of components labelled aba , the two possible solutions are:

  • (ab)a = ba = a with time time(ab) + time(ba) = 5 + 6 = 11.
  • a(ba) = aa = b with time time(ba) + time(aa) = 6 + 3 = 9.

  So the result for this case would be a piece of type b in 9 minutes (denoted 9-b).

Input

The input consists of several test cases. Each test case begins with a line containing a natural number k(  1k26 1≤k≤26 ), followed by a line with k symbols (characters in [a-z]) separated by spaces. The following k lines contain the assembly table: the i-th line has k pairs of the form time-result, where time is an integer between 0 and 1 000 000 inclusive, and result a symbol belonging to the preceding set. The j-th pair in the i-th line represents the time to compose pieces of types represented by the i-th and j-th symbols, along with the type of the resulting piece. After the table, a line with an integer n indicates the number of lines that follow, each line being a string of at most 200 symbols. Each of these lines is a sequence of components that need to be assembled together in the right order.

  The input will finish with a line containing 0, which should not be processed.

Output

  For each test case, print n lines, each with an integer time and a symbol result in the format time-result.Each line represents the minimum time and the type of the resulting piece for the corresponding case in the input. In case of a tie among several possible results with the same minimum time, choose from among those the piece whose type letter appears first in the line that contained the k symbols at the beginning of the test case. (For example, if that line was a c b and both c and b can be obtained with minimum cost 5, print 5-c).

  There must be an empty line between the output of different test cases.

Sample Input

2
a b
3-b 5-b
6-a 2-b
2
aba
bba
2
m e
5-e 4-m
3-e 4-m
1
eme
0

Sample Output

9-b
8-a

7-m


我应该想的出来的呀!定义状态dp[i][j][k]表示区间i~j合成第k个字符需要的最小代价,很简单的n^3的区间dp......比赛的时候还是不敢写。。。诶

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
int cost[128][128],sz,dp[210][210][26],n,m,len;
char sym[26],ch[128][128],str[210];
bool first;

int main(){
    ios_base::sync_with_stdio(false);
    while(cin>>n&&n){
        if(first)
            cout<<endl;
        else
            first=true;

        for(int i=0;i<n;++i)
            cin>>sym[i];
        for(int i=0;i<n;++i)
        for(int j=0;j<n;++j)
            cin>>cost[sym[i]][sym[j]]>>ch[sym[i]][sym[j]]>>ch[sym[i]][sym[j]];

        cin>>m;
        while(m--){
            memset(dp,-1,sizeof dp);
            cin>>str;
            len=strlen(str);
            for(int i=0;i<len;++i)
                dp[i][i][str[i]]=0;
            for(int length=2;length<=len;++length)
            for(int i=0,j=length-1;j<len;++i,++j)
            for(int k=i;k<j;++k)
            for(int le=0;le<n;++le)
            if(dp[i][k][sym[le]]!=-1)
            for(int ri=0;ri<n;++ri)
            if(dp[k+1][j][sym[ri]]!=-1)
            if(dp[i][j][ch[sym[le]][sym[ri]]]==-1||dp[i][j][ch[sym[le]][sym[ri]]]>dp[i][k][sym[le]]+dp[k+1][j][sym[ri]]+cost[sym[le]][sym[ri]])
                dp[i][j][ch[sym[le]][sym[ri]]]=dp[i][k][sym[le]]+dp[k+1][j][sym[ri]]+cost[sym[le]][sym[ri]];

            int ans=-1;
            for(int i=0;i<n;++i)
            if(dp[0][len-1][sym[i]]!=-1)
                ans=(ans==-1?i:(dp[0][len-1][sym[i]]<dp[0][len-1][sym[ans]]?i:ans));
            cout<<dp[0][len-1][sym[ans]]<<'-'<<sym[ans]<<endl;

        }
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值