zoukankan      html  css  js  c++  java
  • sersync自动同步

    sersync项目介绍

          Sersync项目利用inotify与rsync技术实现对服务器数据实时同步的解决方案其中inotify用于监控sersync所在服务器上文件系统的时间变化,rsync是目前广泛使用的本地及异地数据同步工具,其优点是只对变化的目录数据操作,甚至是一个文件不同部门进行同步,所以其优势大大超过使用挂接文件系统或scp等方式进行镜像同步。

    目前使用的比较多的同步程序版本是inotify-tools,另外一个是google开源项目Openduckbill(依赖于inotify-tools),这两个都是基于脚本语言编写的,其设计思路同样是采用inotify与rsync命令。

    相比以上两个项目,sersync项目的优点是:

         ①.使用C++编写,对linux系统文件产生的临时文件和重复的文件操作会进行过滤,在结合rsync同步的时候回减少运行时消耗本地及网络资源,因此速度更快。

         ②.相比较上面两个项目,sersync配置起来很简单:在htto://code.google.com/p/sersync处下载源码(分为32位与64位版本),其中bin目录下是一已经编译好的二进制文件,配合bin目录下的xml文件直接使用即可。

         ③.使用多线程进行 同步(即可以并发同多个不同文件),尤其在同步较大文件时,能够保证多个服务器实时保持同步状态。

         ④.sersync自带出错处理机制,通过失败队列对出错的文件重新同步,如果仍旧失败,则每数个小时对同步失败的文件再重新同步。

         ⑤.Sersync自带crontab功能,只需在xml配置文件中开启,即可按预先的配置,隔一段时间整体同步一次。

         ⑥.Sersync自带socket与http的协议扩展,可以满足有特殊需求的公司二次开发。

    sersync基本架构

         ①.线程组线程是等待线程队列的守护进程,当队列中有数据的时候,线程组守护进程逐个唤醒,当队列中inotify事件较多的时候就会全部唤醒一起工作。这样设计的目的是能够同时处理多个inotify时间,提升服务器的并发同步能力(核数*2+2)

               之所以称止为线程,是因为每个线程在工作的时候,会根据服务上写入文件的数量建立子线程,子线程可以保证所有的文件与各个服务器同时同步,当要同步的文件较大的时候,这样设计可以保证各个远程服务器可以同时获得要同步的文件。

         ②.服务线程的作用有三个:

              a)首先要处理同步失败的文件,将这些文件再次同步,对于再次失败的文件会生成rsync_fail_log.sh脚本,记录失败的事件。

              b)同时每隔10个小时执行脚本一次,同时清空脚本

              c)第三个作用是crontab功能,可以每隔一定事件,将所有路径整体同步一次

        ③.过滤队列的建立是为了过滤短时间内产生的重复的inotify信息,例如在删除文件夹的时候,inotify就会同时产生删除文件夹里的文件和删除文件夹的事件,通过过滤队列,当删除文件夹事件产生的时候,会将之前加入队列的删除文件的事件全部过滤掉,这样只产          生一条删除文件夹事件,从而减轻了同步的负担。同时对于修改文件操作的时候,会产生临时文件的重复操作。

    sersync同步 

        sersync依赖rsync进行数据同步。如下图:在同步主服务器(test3)上开启sersync,sersync负责监控配置路径中的文件系统事件变化,然后调用rsync命令把更新的文件同步到目标服务器(test1-test2),因此,需要在主服务器配置sersync,在同步目标服务器配置rsync server(注意是rsync服务)。

        如图,用户会实时的往左边的同步主服务器(test3)上写入或更新文件数据,此时需要在左边的同步服务器(test3)上配置sersync服务,在左边的同步目标服务器test1和test3服务器上配置rsync守护进程,这样在主服务器test3上产生的写入或更新的文件,就会被sersync服务实时同步到多个目标服务器(test1、test2等)。在主服务器(test3)上有rsync命令即可,在目标服务器(test1、test2)上只需进行简单的配置,并开启rsync守护进程即可。

        提示:学习rsync的守护进程服务后就会发现,实际上sersync就是监控本地的数据写入或更新事件,然后,调用rsync客户端的命令,将写入或更新事件对应的文件通过rsync推送到目标服务(例如test1、test2),就这么简单

    部署环境

    角色

    服务器配置

    操作系统版本

    IP

    机器名

    sersync服务

    VM

    CentOS6.4|2.6.32-358.el6.i686

    192.168.3.102/24

    test3

    rsync服务

    VM

    CentOS6.4|2.6.32-358.el6.i686

    192.168.3.100/24

    test1

    rsync服务

    VM

    CentOS6.4|2.6.32-358.el6.i686

    192.168.3.101/24

    test2

     

    ♧部署rsync服务(在多台目标服务器test1,test2..上相同配置)

    安装

    [root@test1 ~]# yum install -y rsync	#安装rsync             [rsync version 3.0.6]
    [root@test1 ~]# cat >/etc/rsyncd.conf<<EOF
    transfer logging = yes
    log file = /var/log/rsyncd.log
    pid file = /var/run/rsyncd.pid
    lock file = /var/run/rsyncd.lock
    port = 873
    address = 192.168.3.100			#监听的网卡IP,test2上改为192.168.3.101
    uid = root        #rsync是通过这个设定的用户来访问下面配置的path路径
    gid = root		    #所以这个用户要对下面配置的path路径要有相应的权限
    use chroot = no
    read only = false		#设置为false,客户端可以上传文件,设置为true就不能推送只能拉取
    max connections = 2000
    Timeout = 600
    ignore errors
    auth users = rsyncd_bk
    secrets file = /etc/rsyncd.passwd
    hosts allow = 192.168.3.0/255.255.255.0
    hosts deny = *
    list = false
    ########################################				#设置了三个模块
    [www]
    comment = www by heboan
    path = /data0/www/
    ########################################
    [bbs]
    comment = bbs by heboan
    path = /data1/bbs/
    ########################################
    [blog]
    comment = blog by heboan
    path = /data2/blog/
    EOF 

        提示:test1,test2的机器192.168.3.100,192.168.3.101同时部署上诉服务,上面的rsync服务的配置文件,表明允许sersync主服务器(192.168.3.102)访问,rsync同步模块名为[www][bbs][blog],将同步过来的文件分别放入对应path指定的目录/data0/www/,/data1/bbs/,/data2/blog/下。如果有多台目标服务器,则每一台都需要进行类似的rsync服务配置,上面的uid,gid要换成你服务器的相应的同步用户,注意,rsync服务账户(本文用了root)要有对同步目录的写入更新权限。

    创建相关待同步目录

    # mkdir -p /data0/www /data1/bbs /data2/blog
    

    配置相关权限认证

    # echo "rsyncd_bk:pass123" >/etc/rsyncd.passwd
    # chmod 600 /etc/rsyncd.passwd 
    # ll /etc/rsyncd.passwd 
    -rw-------. 1 root root 18 Apr 20 21:31 /etc/rsyncd.passwd
    

    开启rsync守护进程

    # rsync --daemon
    # ps -ef |grep rsync|grep -v grep
    root      1710     1  0 21:32 ?        00:00:00 rsync --daemon
    # netstat -lnt |grep 873
    tcp        0      0 192.168.3.100:873           0.0.0.0:*                   LISTEN
    

    设置开机启动

    # which rsync
    /usr/bin/rsync
    # echo "#rsync service daemon by heboan 20150420" >>/etc/rc.local 
    # echo "/usr/bin/rsync --daemon" >>/etc/rc.local 
    

    重启命令

    # pkill rsync
    # ps -ef |grep rsync|grep -v grep
    # rsync --daemon
    # ps -ef |grep rsync|grep -v grep
    root      1746     1  0 21:43 ?        00:00:00 rsync --daemon
    

    到此test1已经配置完成,test2的配置和test1一样,这里就不再写出步骤,和上面一样即可

     

    ♧在test3上配置rsync客户端

    [root@test3 ~]# yum install -y rsync
    
    在test3上配置rsync客户端相关权限认证
    [root@test3 ~]# echo "pass123" >/etc/rsyncd.passwd
    [root@test3 ~]# chmod 600 /etc/rsyncd.passwd 
    [root@test3 ~]# ll /etc/rsyncd.passwd 
    -rw-------. 1 root root 8 Apr 20 22:21 /etc/rsyncd.passwd
    

    test3上手工测试rsync同步情况

    特别强调:此步非常关键,如果这里测试不成功,后面的sersync配好了也不会同步数据

    ①分别创建待同步的数据

    [root@test3 ~]# mkdir -p /data0/www /data1/bbs /data2/blog
    [root@test3 ~]# touch /data0/www/www.log /data1/bbs/bbs.log /data2/blog/blog.log
    [root@test3 ~]# ls /data0/www/ /data1/bbs/ /data2/blog/
    /data0/www/:
    www.log
    
    /data1/bbs/:
    bbs.log
    
    /data2/blog/:
    blog.log
    

    ②执行同步命令

    rsync -avzP /data0/www/ rsyncd_bk@192.168.3.100::www/ --password-file=/etc/rsyncd.passwd
    rsync -avzP /data0/www/ rsyncd_bk@192.168.3.101::www/ --password-file=/etc/rsyncd.passwd 
    
    rsync -avzP /data1/bbs/ rsyncd_bk@192.168.3.100::bbs/ --password-file=/etc/rsyncd.passwd
    rsync -avzP /data1/bbs/ rsyncd_bk@192.168.3.101::bbs/ --password-file=/etc/rsyncd.passwd 
    
    rsync -avzP /data2/blog/ rsyncd_bk@192.168.3.100::blog/ --password-file=/etc/rsyncd.passwd
    rsync -avzP /data2/blog/ rsyncd_bk@192.168.3.101::blog/ --password-file=/etc/rsyncd.passwd
    

    ③同步完成之后,test1,test2上的对应目录应该有*.log的文件

    [root@test1 ~]# ls /data0/www/ /data1/bbs/ /data2/blog/
    /data0/www/:			/data1/bbs/:			/data2/blog/:
    www.log			       bbs.log			        blog.log
    
    [root@test2 ~]# ls /data0/www/ /data1/bbs/ /data2/blog/
    /data0/www/:			/data1/bbs/:			/data2/blog/:
    www.log				bbs.log				blog.log
    

    ♧在test3上开始部署sersync服务

     

    下载sersync

        在google code下载sersync的可执行文件版本,里面有配置文件与可执行文件,这里用sersync2.5进行说明,新版配置形式类似。

        下载地址:http://sersync.googlecode.com,根据自己的系统版本选择32位或64位的下载

    安装sersync

    [root@test3 ~]# tar zxf sersync2.5_32bit_binary_stable_final.tar.gz -C /usr/local/
    [root@test3 ~]# cd /usr/local/;ls
    bin  etc  games  GNU-Linux-x86  include  lib  libexec  sbin  share  src
    [root@test3 local]# mv GNU-Linux-x86 sersync
    [root@test3 local]# ls sersync/
    confxml.xml  sersync2
    

    规范sersync目录结构

    [root@test3 local]# cd sersync/
    [root@test3 sersync]# mkdir conf bin logs
    [root@test3 sersync]# mv confxml.xml conf
    [root@test3 sersync]# mv sersync2 bin/sersync
    [root@test3 sersync]# tree
    .
    ├── bin
    │   └── sersync
    ├── conf
    │   └── confxml.xml
    └── logs
    

    配置sersync

        因为需要同步三个模块[www]、[bbs]、[blog],这里我们需要创建三个与之对应的配置文件,如果只是同步一个模块,我们只需要一个配置文件confxm.xml就可以了(注意:修改配置文件前记得备份)

    [root@test3 sersync]# cd conf/
    [root@test3 conf]# cp confxml.xml www_confxml.xml
    [root@test3 conf]# cp confxml.xml bbs_confxml.xml
    [root@test3 conf]# cp confxml.xml blog_confxml.xml
    [root@test3 conf]# mkdir bk		#创建一个目录,用来放置备份配置文件的
    [root@test3 conf]# mv confxml.xml  bk/		#把备份的配置文件放入备份目录
    [root@test3 conf]# ls
    bbs_confxml.xml  bk  blog_confxml.xml  www_confxml.xml
    

    修改配置文件www_confxml.xml(bbs_confxml.xml、blog_confxml.xml同理修改)

    ①修改24-28行的部分,原内容为:
     
     24		<localpath watch="/opt/tongbu">
     25		    <remote ip="127.0.0.1" name="tongbu1"/>
     26		    <!--<remote ip="192.168.8.39" name="tongbu"/>-->
     27		    <!--<remote ip="192.168.8.40" name="tongbu"/>-->
     28		</localpath>
     
    修改后的内容为:
            <localpath watch="/data0/www">
                 <remote ip="192.168.3.100" name="www"/>
                 <remote ip="192.168.3.101" name="www"/>
            </localpath>
    提示:此步watch="/data0/www"就是定义服务端待同步的目录,和目标服务器的模块name="www"
    -----------------------------------------------------------------------------------
    bbs_confxml.xml修改为:
           <localpath watch="/data1/bbs">
                 <remote ip="192.168.3.100" name="bbs"/>
                 <remote ip="192.168.3.101" name="bbs"/>
            </localpath>
    
    blog_confxml.xml修改为:
           <localpath watch="/data2/blog">
                 <remote ip="192.168.3.100" name="blog"/>
                 <remote ip="192.168.3.101" name="blog"/>
            </localpath>
    
    ②修改29-35(修改前的行号),认证部分,原内容为:
     29		<rsync>
     30		    <commonParams params="-artuz"/>	#同步的参数
     31		    <auth start="false" users="root" passwordfile="/etc/rsync.pas"/>
     32		    <userDefinedPort start="false" port="874"/><!-- port=874 -->
     33		    <timeout start="false" time="100"/><!-- timeout=100 -->
     34		    <ssh start="false"/>
     35		</rsync>
    
    修改后的内容为:(其他两个配置文件修改为一样即可) <rsync> <commonParams params="-artuz"/> <auth start="true" users="rsyncd_bk" passwordfile="/etc/rsyncd.passwd"/> <userDefinedPort start="false" port="874"/><!-- port=874 --> <timeout start="true" time="100"/><!-- timeout=100 --> <ssh start="false"/> </rsync>

     细心一点我们就能明白,其实上面的几个配置就是在拼接rsync -artuz --timeout=100 /data0/www/ rsyncd_bk@192.168.3.100:www/ --password-file=/etc/rsyncd.passwd这个同步的命令而已

    ③修改36行(修改前的行号),原内容为
    36	     <failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->
    
    修改后的内容为:
         <failLog path="/usr/local/sersync/logs/www_rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->
    
    提示:当同步失败后,日志记录到/usr/local/sersync/logs/www_rsync_fail_log.sh,并且每60分钟对失败的log进行重新同步
    -----------------------------------------------------------------------------------
    bbs_confxml.xml修改为:
         <failLog path="/usr/local/sersync/logs/bbs_rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->
    	 
    blog_confxml.xml修改为:
         <failLog path="/usr/local/sersync/logs/blog_rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->
    

    配置sersync环境变量

    [root@test3 ~]# echo 'export PATH=$PATH:/usr/local/sersync/bin'>>/etc/profile
    [root@test3 ~]# tail -1 /etc/profile
    export PATH=$PATH:/usr/local/sersync/bin
    [root@test3 ~]# source /etc/profile
    [root@test3 ~]# which sersync
    /usr/local/sersync/bin/sersync
    

    启动命令

    sersync -r -d -o /usr/local/sersync/conf/www_confxml.xml
    sersync -r -d -o /usr/local/sersync/conf/bbs_confxml.xml
    sersync -r -d -o /usr/local/sersync/conf/blog_confxml.xml
    
    参数说明:
    -r  :用来第一次同步初始化目录,是服务器两边的内容保持一致
    -d  :在后台运行
    -o  :用来指定配置文件
    

    ♧sersync同步测试(省略)

    附:

    Sersync配置文件说明(XML配置文件:confxml.xml)

    提示:xml配置文件注释不是“#”,而是<!--中间是注释内容-->

    1	<?xml version="1.0" encoding="ISO-8859-1"?>
    2	<head version="2.5">
    3	    <host hostip="localhost" port="8008"></host>
    hostip与port是针对插件的保留字段,对于同步功能没有任何作用,保留默认即可
    4	    <debug start="false"/>
    设置为true,开启debug模式,会在sersync正在运行的控制台打印inotify事件与rsync同步命令
    5	    <fileSystem xfs="false"/>
    对于xfs文件系统的用户,需要将这个选项开启,才能使sersync正常工作
    对于sersync监控的文件,会默认过滤系统的临时文件(以“.”开头,以“~”结尾),除了这些文件外,可以自定义需要过滤的文件
    6	    <filter start="false">
    7		<exclude expression="(.*)\.svn"></exclude>
    8		<exclude expression="(.*)\.gz"></exclude>
    9		<exclude expression="^info/*"></exclude>
    10		<exclude expression="^static/*"></exclude>
    11	    </filter>
    将start设置为true后开启过滤功能,在exclude标签中,填写正则表达式,默认给出两个例子分别是过滤以“.gz”结尾的文件与过滤监控目录下的info路径(监控路径/info/*),可以根据需要添加,但开启的时候,自己测试一下,正则表达式如果出现错误,控制台会有提示。相比较使用rsync的exclude功能,被过滤的路径,不会加入监控,大大减少了rsync同步的通讯量
    对于inotify监控参数可以进行设置,根据项目的特点优化rsync
    12	    <inotify>
    13		<delete start="true"/>
    14		<createFolder start="true"/>
    15		<createFile start="false"/>
    16		<closeWrite start="true"/>
    17		<moveFrom start="true"/>
    18		<moveTo start="true"/>
    19		<attrib start="false"/>
    20		<modify start="false"/>
    21	    </inotify>
    对于大多数应用,可以尝试把createFile(监控文件事件选项)设置为false来提高性能,减少rsync通讯。因为拷贝文件到监控目录会产生create事件与close_write事件,所以如果关闭create事件,只监控文件拷贝结束时的事件close_write,同样可以实现文件完整同步。
    注意:需要将createFolder保持为true,如果将createFolder设为false,则不会对产生的目录进行监控,该目录下的子文件与子目录也不会被监控。所以除非特殊需要,请开启。默认情况下对创建文件(目录)事件与删除文件(目录)事件都进行监控,如果项目中不需要删除远程目标服务器的文件(目录),则可以将delete参数设置为false,则不对删除事件进行监控。
    22	
    23	    <sersync>
    文件监控与远程同步设置
    24		<localpath watch="/opt/tongbu">
    25		    <remote ip="127.0.0.1" name="tongbu1"/>
    26		    <!--<remote ip="192.168.8.39" name="tongbu"/>-->
    27		    <!--<remote ip="192.168.8.40" name="tongbu"/>-->
    28		</localpath>
    /opt/tongbu目录为sersync主服务器本地待同步的目录,ip=”192.168.8.39”为从服务器的IP地址,如果有多个从服务器,依次列出来即可。name=”tongbu”,这里的tongbu为rsyncd.conf中的模块名字,即中括号中的名称
    Rsync设置
    29		<rsync>
    30		    <commonParams params="-artuz"/>
    31		    <auth start="false" users="root" passwordfile="/etc/rsync.pas"/>
    32		    <userDefinedPort start="false" port="874"/><!-- port=874 -->
    33		    <timeout start="false" time="100"/><!-- timeout=100 -->
    34		    <ssh start="false"/>
    35		</rsync>
    在commonParams项,我们可以自定义rsync的同步参数,默认是-artuz,auth start=”false”设置为true的时候,使用rsync的认证模式传送,需要配置user与passwordfile(--password-file=)来使用。userDenfinedPort当远程同步目标服务器的rsync端口不是默认端口的时候使.timeout这是rsync的timout事件。<ssh start=”false”/>如果开启,ssh使用rsync -e ssh的方式传输。
    失败日志脚本配置
    36		<failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->
    如果文件同步传输失败,会重新传送,再次失败就会写入rsync_fail_log.sh,然后每个一段时间(timeToExecute进行设置)执行该脚本再次重新传送,然后清空该脚本。可以通过path来设置日子路径。
    Crontab定期整体同步功能
    37		<crontab start="false" schedule="600"><!--600mins-->
    38		    <crontabfilter start="false">
    39			<exclude expression="*.php"></exclude>
    40			<exclude expression="info/*"></exclude>
    41		    </crontabfilter>
    42		</crontab>
    Crontab可以对监控路径与远程目标主机每隔一段时间进行一次整体同步,可能由于一些原因再次重传失败,这个时候如果开启了crontab功能,还可以进一步保证各个服务器文件一致,如果文件量比较大,crontab的时间间隔要设大一些,否则可能增加通讯开销。Schedule这个参数设置crontab的时间间隔,默认是600分钟。如果开启了filter文件过滤功能,那么crontab整体同步也需要设置过滤,否则虽然实时同步的文件被过滤了,但是crontab整体同步的时候,如果不单独设置crontabfilter,还会将需过滤的文件同步到远程从服务器,,crontab的过滤正则与filter过滤的不同,也给出了两个实例分别对应与过滤文件与目录。总之如果同时开启了filter与crontab,则要开启crontab的crontabfilter,并按示例设置使其与filter的过滤一一对应。
    插件设置
    43		<plugin start="false" name="command"/>
    当start=”false”处设置为true的时候,将文件同步到远程服务器后会调用插件。通过name参数指定需要执行的插件。目前支持的有command refreshCDN socket http四种插件。其中,http插件目前由于兼容性原因已经去除,以后会重新加入
    44	    </sersync>
    45	
    Command插件
    46	    <plugin name="command">
    47		<param prefix="/bin/sh" suffix="" ignoreError="true"/>	<!--prefix /opt/tongbu/mmm.sh suffix-->
    48		<filter start="false">
    49		    <include expression="(.*)\.php"/>
    50		    <include expression="(.*)\.sh"/>
    51		</filter>
    52	    </plugin>
    当文件同步完成后,会调用command插件,如同步文件时test.php,则test.php文件再改动之后,调用rsync同步到远程服务器后,调用command插件,执行 :/bin/sh test.php  suffix>dev/null 2>&1
    如果suffix设置了,则会放在inotify事件test.php之后,如果ignoreError为true,则会添加>/dev/null 2>&1,当然还可以设置command的filter,当filter为true时,include可以只对正则匹配到的文件调用command.
    53	
    Socke插件,开启该模块,则向指定的ip与端口发送inotify所产生的文件路径信息
    54	    <plugin name="socket">
    55		<localpath watch="/opt/tongbu">
    56		    <deshost ip="192.168.138.20" port="8009"/>
    57		</localpath>
    58	    </plugin>
    59	    <plugin name="refreshCDN">
    60		<localpath watch="/data0/htdocs/cms.xoyo.com/site/">
    61		    <cdninfo domainname="ccms.chinacache.com" port="80" username="xxxx" passwd="xxxx"/>
    62		    <sendurl base="http://pic.xoyo.com/cms"/>
    63		    <regexurl regex="false" match="cms.xoyo.com/site([/a-zA-Z0-9]*).xoyo.com/images"/>
    64		</localpath>
    “refreshCDN”,就在同步过程中将文件发送到目的服务器后刷新cdn接口。如果不想使用,则将start属性设为false即可。
    如果需要使用其他插件,则查看其他plugin标签,将插件名称改为xml中其他插件名称即可。该模块根据chinaCDN的协议进行设计,当有文件产生的时候,就向cdn接口发送需要刷新的路径位置。
    其中localpath watch=”/data0/hotdocs/cms.xoyo.com/site”是需要监控的目录。cdninfo标签制定了cdn接口的域名,端口号,以及用户名与密码。
    sendurl标签是需要刷新的url的前缀。regexurl标签中的,regex属性为true的时候,使用match属性的正则语句匹配inotify返回的路径信息,并将正则匹配到的部分作为url一部分。
    举例:
    如果产生的文件事件为:/data0/htdoc/cms.xoyo.com/site/jx3.xoyo.com/image/a/123.txt
    经过上面的match正则匹配后,最后的刷新路径是:http://pic.xoyo.com/cms/jx3/a/123.txt
    如果regex属性为false,最后刷新的路径是http://pic.xoyo.com/cms/jx3.xoyo.com/images/a/123.txt
    65	    </plugin>
    66	</head>
    
    ###############################################################################################
    只调用command插件
    ./sersync -d -m command
    只调用refreshCDN插件
    ./sersync -d -m refreshCDN
    只调用socket插件
    ./sersync -d -m socket
  • 相关阅读:
    【UVA116】 单向TSP Unidirectional TSP [动态规划]
    【luogu4408】 [NOI2003]逃学的小孩 [动态规划 树的直径]
    【POJ2631】树的直径 [动态规划 树形dp]
    【luogu 1156】 垃圾陷阱 [动态规划 背包]
    【luogu1472】 奶牛家谱 Cow Pedigrees [动态规划]
    【luogu2747】 [USACO5.4]周游加拿大Canada Tour[动态规划]
    【luogu2737】 [USACO4.1]麦香牛块Beef McNuggets [动态规划 完全背包][数学 扩展欧几里德]
    【luogu3856】【TJOI2008】公共子串 [动态规划]
    【luogu1020】 导弹拦截 [动态规划LIS]
    【luogu1439】 【模板】最长公共子序列 [动态规划][LIS最长上升子序列][离散化]
  • 原文地址:https://www.cnblogs.com/sellsa/p/5345092.html
Copyright © 2011-2022 走看看