ZJU1876 Edit Step Ladders - 动态规划 最长序列+二分优化

ZJU1876 PKU2564 Edit Step Ladders

题目大意:

如果单词A和单词B可以通过增加、删除、或修改一个字母而得到,并且A排在B之前,那么说A可以到达B。字典序给出n个单词(n<=25000),要求最长的可到达的单词串的长度。

分析:

这是很经典的最长非降子序列问题的变形,但由于单词和单词之间的比较没有偏序关系,所以不能使用O(nlogn)的LIS算法。用最直接的O(n^2)的算法可以求解。

设f[i]表示以第i个单词结尾的最长序列的长度。初始时f[0]=1。单词序列为a[i]

状态转移方程:f[i] = max{ f[j]+1 ,(0<=j<i, a[i]和a[j]可达) }

判断两个单词是否可达需要O(len(a[i]))的时间。

这样做不管怎么优化,最终还是TLE了……

这种最直接的做法没有充分利用到题目中的信息:“单词以字典序给出”。显然,这个性质可以用来二分查找。现在的问题是,有什么东西需要查找呢?

由于单词和单词之间可达只有三种变形方式,增加字母,删除字母,改变字母。如果单词a[i]要在前面i-1个单词中寻找一个可达的单词a[j],那么a[j]必然比a[i]字典序小。

所以我们可以考虑在计算f[i]时,枚举所有a[i]变形得到的单词s,然后在前i-1个单词中二分查找s是否存在。若a[j]==s那么a[i]可以接到a[j]后面。

这里有个必须加入的剪枝就是,枚举时按照字典序从小到大枚举s,当s大于a[i]时就退出当前枚举。因为按照题信息,a[i]之前的单词必定是字典序小于a[i]的。我尝试去掉这个剪枝,结果还是TLE了……

这样做在ZJU用时2.9s,在PKU要快一些。

查找单词s是否存在这个问题还可以用更高效的Trie Tree来实现。不是很熟……

花絮:

总是训练的时候做不出来,晚上睡觉的时候就能想到解法……

----------------------------------------------------------------------------------------------------------

/*
ZJU1876 Edit Step Ladders
*/

#include <stdio.h>
#include <string.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
 
#define N 25005
#define L 20

char a[N][L];
int f[N]={0},max;
char CH[]={'z','a','z'};


int bsearch(char a[][L],int n,char s[]){
    int l=0,r=n-1,mid,k;
    if(l>r) return -1;
    while(l<=r){
        mid=(l+r)/2;
        k=strcmp(a[mid],s);
        if(k==0) return mid;
        if(k>0) r=mid-1;
        if(k<0) l=mid+1;
    }
    return -1;
}

void add(char s[],int k,char ch,char t[]){
    int i;
    for(i=0;i<k;i++) t[i]=s[i];
    t[k]=ch;
    for(i=k;s[i];i++) t[i+1]=s[i];
    t[i+1]='/0';
}

void del(char s[],int k,char t[]){
    int i;
    for(i=0;i<k;i++) t[i]=s[i];
    for(i=k+1;s[i];i++) t[i-1]=s[i];
    t[i-1]='/0';
}

void change(char s[],int k,char ch,char t[]){
    int i;
    for(i=0;s[i];i++) t[i]=s[i];
    t[k]=ch;
    t[i]='/0';
}

void edit(int e,char s[],int k,char ch,char t[]){
    if(e==0) add(s,k,ch,t);
    if(e==1) del(s,k,t);
    if(e==2) change(s,k,ch,t);
}

int main()
{
    int i,j,k,m,n=0,e;
    char s[L],ch;

   
    //input
    while(scanf("%s",a[n])!=EOF) n++;

    //DP
    f[0]=1; max=1; c[0]=1;
    for(i=1;i<n;i++){
        f[i]=1;
        //edit words
        for(e=0;e<3;e++){   //0:add 1:del 2:change
            for(k=0;a[i][k];k++){
                for(ch='a';ch<=CH[e];ch++){
                    edit(e,a[i],k,ch,s);
                    if(strcmp(s,a[i])>=0) break;
                    j=bsearch(a,i,s);
                    if(j>=0&&f[i]<f[j]+1){
                        f[i]=f[j]+1;
                        if(max<f[i]) max=f[i];
                    }
                }
            }
        }
    }
   
    //output
    printf("%d/n",max);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
ZJU-I型机械臂是一种由浙江大学机器人研究所开发的六自由度机械臂,具有高速、精度和可靠性等特点。机械臂的运动控制是机器人中的重要研究领域之一,其中点到点轨迹规划是机器人在运动过程中最基础和常用的一种方式,也是机械臂控制的核心问题之一。 点到点轨迹规划的目标是通过给定的起点和终点,计算出机械臂的运动轨迹,使机械臂在运动过程中满足机械臂轨迹的连续性、平滑性、可控性等要求。在过去的研究中,经典的点到点轨迹规划方法包括插值法、线性规划法、最小能量法等。 如果使用Python实现机械臂的点到点轨迹规划,可以采用Robotics Toolkit(简称robot)这个模块。robot模块提供了各种从轨迹规划、控制到仿真的功能,可用于ROS、Vrep、Webots等机器人仿真软件。使用robot模块,可以通过几行代码实现机械臂的点到点轨迹规划,例如: ``` from roboticstoolkit import robot from roboticstoolkit.robots import zju # 初始化机器人 zju_arm = robot.Robot('zju', zju.URDF) # 设定起点和终点 start = [0, 0, 0, 0, 0, 0] goal = [0, 1, 1, 0.5, 0, 0] # 计算机械臂的轨迹 path = zju_arm.get_trajectory(start, goal) # 控制机械臂运动到终点 zju_arm.move_to(goal) ``` 其中,`roboticstoolkit`和`roboticstoolkit.robots`都是导入的Python模块,`zju`是机械臂的URDF定义文件,`start`和`goal`是起点和终点的坐标,`get_trajectory()`函数会返回计算得到的机械臂轨迹,`move_to()`函数则控制机械臂运动到终点。 总之,使用Python实现ZJU-I型机械臂的点到点轨迹规划相对简单,只需要导入相应的模块,并根据需要设置机械臂的各种参数,即可轻松实现机械臂的控制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值