ZSTU 4514: yesky wine锦鲤卡 (线性dp)

题目链接

题面:
4514: yesky wine锦鲤卡
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 28 Solved: 6
Description

懒羊羊的红酒供应系统优化完成了。懒羊羊好开心!他决定给所有ACMer和OIer包括教练一个机会,幸运者可以取得yesky wine锦鲤卡,免费供应一年的yesky wine。要取得锦鲤卡,需要通过一个游戏,谁是第一个取得游戏的胜利者,就可以拿走锦鲤卡。
游戏的目标很简单,用最少的回合完成红酒瓶游戏。
总共有2排,每排放了一些红酒瓶和木牌。每个红酒瓶上写了一个小写字母,每个木牌上写了一个数。
每个游戏者可以对这2排红酒瓶和木牌进行如下操作:
1 放置红酒瓶。游戏者可以找懒羊羊要1个自己想要字母的酒瓶,然后把它放到任意一行的任意位置。
2 换走木牌。游戏者可以从2排里取走一个木牌,并且向懒羊羊要木牌上写得数字一样多的任意字母的酒瓶,然后把刚才换来的酒瓶按照自己想要的顺序放在原来木牌位置。
3 拿走红酒瓶。游戏者可以拿走任意一个红酒瓶,把它扔在懒羊羊边上的垃圾桶里。
哪个游戏者用最少的操作步数完成,并且是第一个完成的,他就可以拿走锦鲤卡。完成的目标是2排只剩红酒瓶,而且红酒瓶上相对应的字母是一样的。

Input

输入2行,每行仅包含小写字母或0到9的数字
第一行长度最小1,最大不超过10000,第二行长度是1到1000之间,每行的数字不超过100个。

Output

输出最少操作次数

Sample Input

【输入样例1】
wine
4
【输入样例2】
wine5ing
4drinking

Sample Output

【输出样例1】
1
【输出样例2】
2

题解:
最终木牌一定会被替换为红酒瓶,且木牌替换的红酒瓶可以任意。
那么我们上来,先将木牌全部替换为 k 个 ? 表示该处可以放置 k 个任意的红酒瓶。其中 k 为木牌上的数字。
那么现在问题变成,我现在有两个字符串,我可以在任意一个串中的任意位置添加一个字符或者删除任意一个字符,问两个串变得一样需要的步数。
这个问题实际上就是求最长公共子序列的长度。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<set>
#define ll long long
#define pr make_pair
#define pb push_back
#define ui unsigned int
#define lc (cnt<<1)
#define rc (cnt<<1|1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007;
const double eps=1e-8;
const double dnf=1e20;
const double pi=acos(-1.0);
const int maxn=20100;
const int maxm=20100;
const int up=100;
const int maxp=1100;
int dp[18010][1810];
char str1[maxn],str2[maxn];
char a[maxn],b[maxn];
int cnta=0,cntb=0;
int main(void)
{
    scanf("%s%s",str1,str2);
    int lena=strlen(str1);
    int ans=0;
    for(int i=0;i<lena;i++)
    {
        if(str1[i]>='0'&&str1[i]<='9')
        {
            for(int j=1;j<=str1[i]-'0';j++)
                a[++cnta]='?';
            ans++;
        }
        else a[++cnta]=str1[i];
    }
 
    int lenb=strlen(str2);
    for(int i=0;i<lenb;i++)
    {
        if(str2[i]>='0'&&str2[i]<='9')
        {
            for(int j=1;j<=str2[i]-'0';j++)
                b[++cntb]='?';
            ans++;
        }
        else b[++cntb]=str2[i];
    }
    for(int i=1;i<=cnta;i++)
    {
        for(int j=1;j<=cntb;j++)
        {
            if(a[i]==b[j]||a[i]=='?'||b[j]=='?')
                dp[i][j]=dp[i-1][j-1]+1;
            else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        }
    }
    printf("%d\n",cnta+cntb-dp[cnta][cntb]*2+ans);
    return 0;
 
}

当然也可以直接dp求。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<set>
#define ll long long
#define pr make_pair
#define pb push_back
#define ui unsigned int
#define lc (cnt<<1)
#define rc (cnt<<1|1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007;
const double eps=1e-8;
const double dnf=1e20;
const double pi=acos(-1.0);
const int maxn=20100;
const int maxm=20100;
const int up=100;
const int maxp=1100;
int dp[10810][1810];
char str1[maxn],str2[maxn];
char a[maxn],b[maxn];
int cnta=0,cntb=0;
int main(void)
{
    scanf("%s%s",str1,str2);
    int lena=strlen(str1);
    int ans=0;
    for(int i=0;i<lena;i++)
    {
        if(str1[i]>='0'&&str1[i]<='9')
        {
            for(int j=1;j<=str1[i]-'0';j++)
                a[++cnta]='?';
            ans++;
        }
        else a[++cnta]=str1[i];
    }
 
    int lenb=strlen(str2);
    for(int i=0;i<lenb;i++)
    {
        if(str2[i]>='0'&&str2[i]<='9')
        {
            for(int j=1;j<=str2[i]-'0';j++)
                b[++cntb]='?';
            ans++;
        }
        else b[++cntb]=str2[i];
    }
    for(int i=0;i<=cnta;i++)
        dp[i][0]=i;
    for(int i=0;i<=cntb;i++)
        dp[0][i]=i;
    for(int i=1;i<=cnta;i++)
    {
        for(int j=1;j<=cntb;j++)
        {
            if(a[i]==b[j]||a[i]=='?'||b[j]=='?')
                dp[i][j]=dp[i-1][j-1];
            else dp[i][j]=min(dp[i-1][j],dp[i][j-1])+1;
        }
    }
    printf("%d\n",dp[cnta][cntb]+ans);
    return 0;
 
}

后记:
2019年第十届蓝桥杯C/C++B组决赛的第一个编程题好像就是这个,但是当时不会做,唉。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值