uva1625 color length

175 篇文章 0 订阅
137 篇文章 0 订阅

Cars painted in different colors are moving in a row on the road as
shown in Figure 1. The color of each car is represented by a single
character and the distance of two adjacent cars is assumed to be 1.
Figure 1 shows an example of such cars on the road. For convenience,
the numbers in Figure 1 represent the locations of each car. Figure 1.
Cars in different colors on the road For any color c , location ( c )
represents set of the locations of the cars painted in color c and
color length L ( c ) is de ned as follows: L ( c ) = max location ( c
)

动态规划。
dp[i][j]表示两个字符串分别进行到第i位和第j位的最小费用。
那么一定是从dp[i][j-1]或dp[i-1][j]转移而来。因为每个颜色的长度只和开始位置和结束位置有关,所以从某一个位置转移而来的话,该位置所有已开始而未结束的颜色的长度都要加一。
那么就需要预处理出每个位置已开始而未结束的颜色的个数。不妨记为cnt[i][j],则一定从cnt[i-1][j]或cnt[i][j-1]转移而来。注意这一次不是取最小值,而是在有意义的情况下任取即可,因为每个位置的个数是一定的,不存在最优化问题。
为了求cnt数组,有需要进行预处理。记下每个字符串中每种颜色的起始和结束位置,不妨考虑由cnt[i-1][j]转移而来,cnt[i][j-1]同理。
如果i是某个颜色的起始的话,那就在之前基础上加一。如果是末尾的话,要减一。【注意这里说的起始和末尾是整个序列的,而不是他所在字符串的。】
得到cnt数组之后,便可以计算dp数组了。
dp[i][j]=min(dp[i-1][j]+cnt[i][j-1],dp[i][j-1]+cnt[i][j-1])。
注意边界条件。
注意区间首尾和边界。
不要用memset。(除非用滚动数组)

#include<cstdio>
#include<cstring>
#define M(a) memset(a,0,sizeof(a))
int min(int x,int y){return x<y?x:y;}
int dp[5010][5010],bg[2][30],ed[2][30],cnt[5010][5010];
char s[2][5010];
const int oo=0x7f7f7f7f;
int main()
{
    int i,j,k,l[2],m,n,p,q,x,y,z,T,cnt1,cnt2;
    char c;
    scanf("%d",&T);
    while (T--)
    {
        M(bg);
        M(ed);
        for (i=0;i<2;i++)
        {
            scanf("%s",s[i]+1);
            l[i]=strlen(s[i]+1);
            for (j=1;j<=l[i];j++)
              if (!bg[i][s[i][j]-'A'+1])
                bg[i][s[i][j]-'A'+1]=j;
            for (j=l[i];j>=1;j--)
              if (!ed[i][s[i][j]-'A'+1])
                ed[i][s[i][j]-'A'+1]=j;
        }
        for (i=0;i<=l[0];i++)
          for (j=0;j<=l[1];j++)
            if (i)
              cnt[i][j]=cnt[i-1][j]
                +(bg[0][s[0][i]-'A'+1]==i&&(bg[1][s[0][i]-'A'+1]>j||bg[1][s[0][i]-'A'+1]==0))
                -(ed[0][s[0][i]-'A'+1]==i&&(ed[1][s[0][i]-'A'+1]<=j||ed[1][s[0][i]-'A'+1]==0));
            else
              if (j)
                cnt[i][j]=cnt[i][j-1]
                  +(bg[1][s[1][j]-'A'+1]==j&&(bg[0][s[1][j]-'A'+1]>i||bg[0][s[1][j]-'A'+1]==0))
                  -(ed[1][s[1][j]-'A'+1]==j&&(ed[0][s[1][j]-'A'+1]<=i||ed[0][s[1][j]-'A'+1]==0));
        for (i=0;i<=l[0];i++)
          for (j=0;j<=l[1];j++)
            if (i||j)
            {
                x=y=oo;
                if (i) x=dp[i-1][j]+cnt[i-1][j];
                if (j) y=dp[i][j-1]+cnt[i][j-1];
                dp[i][j]=min(x,y);
            }
        printf("%d\n",dp[l[0]][l[1]]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值