代码自动上线功能

企业部署代码上线是件比较麻烦的事情,还好我们有jenkins这个持续集成的软件可以帮助我们做很多的事情,现在我们就

来测试用jenkins推送代码上线。

我们这里测试的是一个html的web页面监控的代码上线,做一个简单的小教程,先不涉及动态语言和数据库。

准备环境

准备三台服务器

服务器名称 ip地址 需要的服务 系统
git 10.0.0.200 gitlab centos7
jenkins 10.0.0.201 jenkins centos7
web01 10.0.0.7 nginx centos7

GitLab

GitLab简介

GitLab 是一个用于仓库管理系统的开源项目。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。可

通过Web界面进行访问公开的或者私人项目。它拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可

以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。团队成员可以利用内置的简单聊

天程序(Wall)进行交流。它还提供一个代码片段收集功能可以轻松实现代码复用。

常用的网站:

官网:https://about.gitlab.com/

国内镜像:https://mirrors.tuna.tsinghua.edu.cn/gitlab‐ce/yum/

安装环境

1、 CentOS 6或者7

2、 2G内存(实验)生产(至少4G)

3、 安装包:gitlab‐ce‐10.2.2‐ce

4、 禁用防火墙,关闭selinux

https://about.gitlab.com/installation/#centos‐7 # git官网

1、安装gitlab

[root@git ~]# yum install policycoreutils-python -y       # 安装依赖
rz ‐bye gitlab‐ce‐10.2.2‐ce.0.el7.x86_64.rpm # 上传gitlab安装包 下载方式可通过
国内清华源gitlab‐ce社区版本下载
[root@git ~]# rpm -ivh gitlab-ce-10.2.2-ce.0.el7.x86_64.rpm #安装gitlab

2、更改gitlab配置文件

[root@git ~]# vim /etc/gitlab/gitlab.rb
更改url地址为本机IP地址 external_url 'http://10.0.0.200'

3、gitlab命令及文件

gitlab‐ctl reconfigure                  # 更改配置文件后需重新配置
/opt/gitlab/   # gitlab的程序安装目录
/var/opt/gitlab # gitlab目录数据目录
/var/opt/gitlab/git‐dfata # 存放仓库数据
gitlab‐ctl status # 查看目前gitlab所有服务运维状态
gitlab‐ctl stop # 停止gitlab服务
gitlab‐ctl stop nginx # 单独停止某个服务
gitlab‐ctl tail   # 查看所有服务的日志

4、Gitlab的服务构成

nginx: 静态web服务器

gitlab-workhorse: 轻量级的反向代理服务器

logrotate:日志文件管理工具

postgresql:数据库

redis:缓存数据库

sidekiq:用于在后台执行队列任务(异步执行)。(Ruby)

unicorn:An HTTP server for Rack applications,GitLab Rails应用是托管在这个服务器上面的。(Ruby

Web Server,主要使用Ruby编写)

gitlab汉化

首先要有git命令

yum install git -y

1、下载汉化补丁

git clone https://gitlab.com/xhang/gitlab.git

2、查看全部分支版本

git branch ‐a

3、对比版本、生成补丁包

git diff remotes/origin/10-2-stable remotes/origin/10‐2‐stable‐zh > ../10.2.2‐zh.diff

4、停止服务器

gitlab-ctl stop

5、打补丁

patch -d /opt/gitlab/embedded/service/gitlab‐rails -p1 < /tmp/10.2.2-zh.diff

6、启动和重新配置

gitlab-ctl start
gitlab-ctl reconfigure

gitlba的网页操作

通过浏览器输入IP地址进行访问gitlab

10.0.0.200

1、设置密码

2、修改外观(也可不修改,只是为了美观)

效果图

3、添加群组和用户

1、添加群组

2、添加用户

3、修改用户密码

添加用户到群组并给与开发权限

4、创建仓库(项目)

1、手动创建

2、克隆一个项目,这里我们直接克隆一个别人的项目

https://gitee.com/explore/starred/manage-monitor?lang=Html

1.先去上面网站复制克隆地址

2.我们选择克隆方式,选择组为刚创建的组,项目名称自定义,我们这里用的是monitor

3.创建成功

5、设置分支保护(这是网页远程仓库操作,本地服务器操作上一篇git使用中有讲解)

正常情况下,我们是不允许在master分支上修改内容的,我们只能创建新的分支修改,修改完成后进行合并,这里我们做分支保护的目的是为了让其他用户如dev用户在修改完代码内容之后,发起合并请求,root用户进行审核完成才能进行合并

1、无分支保护情况

我们首先登陆dev用户,要了解dev是开发用户,root是老大,老大一般做审核,拥有最高权限

退出root用户

dev用户登录时需要重新编辑一次密码

登录成功后打开我们的项目

首先创建一个新的分支,在新分支上修改内容

我们随便在test分支上修改一个内容

这里我们给他加了一个对不起

现在我们请求合并分支

提交完合并请求会发现我们现在是可以合并的,因为没有设分支保护

我们查看一下master分支,已经合并成功

2、有分支保护情况

登录root用户设置分支保护

选择保护master分支

设置成功

这时我们推出root用户,登录dev用户,继续测试一下,修改test下404.html,这里我们又加了个“保护”

然后我们合并请求(步骤和上面一样),这时我们不能进行合并,因为有保护,只能root账户老大进行合并

登录到root账户,查看并合并请求

合并成功查看一下效果

jenkins

jenkin简介

官网 https://jenkins.io/

Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开

放易用的软件平台,使软件的持续集成变成可能。

1、安装准备

准备jenkins服务器关闭selinux和防火墙

内存2G 50G+硬盘

jenkins 10.0.0.201

2、安装JDK运行环境和jenkins服务

上传JDK和jenkins rpm安装包,使用rpm ‐ivh进行安装,安装完JDK运维java测试是否安装成功

[root@jenkins ~]# rpm -ivh jdk-8u181-linux-x64.rpm
[root@jenkins ~]# rpm -ivh jenkins-2.99-1.1.noarch.rpm

3、配置jenkins

[root@jenkins ~]# vim /etc/sysconfig/jenkins
启动用户修改为root
JENKINS_USER="root"

4、启动jenkins并加入开机自启

[root@jenkins ~]# systemctl start jenkins
[root@jenkins ~]# systemctl enable jenkins

jenkins网页操作

访问页面进行配置

默认端口是8080

http://10.0.0.201:8080

1、在服务器上查看jenkins提示的文件,把密码粘贴到网页

[root@jenkins ~]# cat /var/lib/jenkins/secrets/initialAdminPassword
91e0de6b56374365be1da3ee2ed75254

登录中,可能需要等一段时间

2、进入后我们先跳过安装插件界面

开始使用jenkins

成功进入jenkins主界面

3、我们可以再这里先修改一下密码(也可忽略)

4.插件安装

安装完插件查看一下

插件安装目录

[root@jenkins jenkins]# ll /var/lib/jenkins/plugins
总用量 80936
drwxr-xr-x 7 jenkins jenkins 124 12月 3 2017 ace-editor
-rw-r--r-- 1 jenkins jenkins 4279042 12月 3 2017 ace-editor.jpi
drwxr-xr-x 4 jenkins jenkins 56 12月 3 2017 ant
drwxr-xr-x 4 jenkins jenkins 56 12月 3 2017 antisamy-markup-formatter
-rw-r--r-- 1 jenkins jenkins 112796 12月 3 2017 antisamy-markup-formatter.jpi
-rw-r--r-- 1 jenkins jenkins 81259 12月 3 2017 ant.jpi
drwxr-xr-x 4 jenkins jenkins 56 12月 3 2017 apache-httpcomponents-client-4-api
-rw-r--r-- 1 jenkins jenkins 1407235 12月 3 2017 apache-httpcomponents-client-4-api.jpi
drwxr-xr-x 4 jenkins jenkins 56 12月 3 2017 authentication-tokens
-rw-r--r-- 1 jenkins jenkins 14638 12月 3 2017 authentication-tokens.jpi
drwxr-xr-x 4 root root 56 12月 7 2017 blueocean-commons
-rw-r--r-- 1 root root 1540739 12月 7 2017 blueocean-commons.jpi

jenkins主要的目录

/usr/lib/jenkins/:jenkins安装目录,WAR包会放在这里
/etc/sysconfig/jenkins:jenkins配置文件,“端口”,“JENKINS_HOME”等都可以在这里配置
/var/lib/jenkins/:默认的JENKINS_HOME
/var/log/jenkins/jenkins.log:Jenkins日志文件

5、创建一个自由风格的项目freestyle‐job

1、配置项目,丢失旧的构建

2、源码管理将gitlab仓库和jenkins关联

这里我们需要吧jenkins服务器的公钥给gitlab

jenkins端生成公钥

[root@jenkins ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:rm4L5a3Of3URrgcywqOKZtsda5eWoBzZiBsJn/HFztE root@jenkins
The key's randomart image is:
+---[RSA 2048]----+
| |
| . |
| . o . . |
|. . + E o . o |
| o * B.oSo o o . |
| * =o*o o o |
| =.+o.oo . o |
| =.++o== . |
| o...=X=.. |
+----[SHA256]-----+

查看公钥

[root@jenkins ~]# cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHKs/orwn138ROGQicn8yiku6xB0Sn7dqty5KRpE9kc7Z6QFHMms/XWiZetsaGv+uKq9XDExF+5Tt1J6nCHEmrImstr17/u5uSr+YH/9LWxxv5SDJphdwwkUeoN+xMcQ/uJ5r8aWnCfS4wKoPXpoYe22AokkQ4RuxoAud6ZxLU5Bo0rJx3Q8WI0ew67SBI6bxRkwdgjmJhNsZiI8vsEKhZDW8kNlYTz8WuW9jBI/V+qewUeKDiS0O+zbrE7qMhtB+Rj9R/jEHOgOi2ucINWKaOkL7H8rmlhK3WFi3gVmX8Bj6otg2q7HfjZlBXY9sx28U2f8vzOEoGYiM+546PKM6F root@jenkins

把公钥给gitlab

jenkins关联gitlab

这里报错原因是第一次连接他会有一个确认服务器主机的操作,我们需要确认一下

复制上面的报错,如果出现确认主机情况就输入yes

[root@jenkins ~]# git ls-remote -h git@10.0.0.200:zeq/monitor.git
742c1e0055ccdd69c9626052b5463ed5337ad0c9 refs/heads/master

然后我们删除url重新粘贴一遍就好了

3、构建触发器

选择第四个,点击高级

过滤master分支,生成token

4、添加gitlab端web钩子

复制jenkins项目url和token

添加到gitlab

5、添加构建

在jenkins服务器上创建一个脚本目录

[root@jenkins ~]# mkdir /server/scripts -p

编写一个脚本,把从gitlab拉取过来的代码推送到web服务器上

[root@jenkins ~]# vim /server/scripts/do.sh
#!/bin/sh
DATE=$(date +%Y-%m-%d-%H-%M-%S)
CODE_DIR="/var/lib/jenkins/workspace/freestyle-job"
WEB_DIR="/code"
IP=10.0.0.7 get_code_tar(){
cd $CODE_DIR && tar zcf /opt/web-$DATE.tar.gz ./*
} scp_code_web(){
scp /opt/web-$DATE.tar.gz $IP:$WEB_DIR
} code_tarxf(){
ssh $IP "cd $WEB_DIR &&mkdir web-$DATE && tar xf web-$DATE.tar.gz -C web-$DATE" }
ln_html(){
ssh $IP "cd $WEB_DIR && rm -rf html && ln -s web-$DATE html"
} main(){ get_code_tar;
scp_code_web;
code_tarxf;
ln_html;
}
main

因为要推送到web服务器上,我们要把公钥给web服务器

[root@jenkins ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.0.0.7

增加构建步骤

jenkins自由风格项目创建完成,接下来我们开始配置web服务器

web服务器操作

因为我们最终操作是实现代码自动上线到web服务器,我们要配置web服务器

1.安装nginx扩展源

[root@web01 ~]# vim /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

2、安装nginx

[root@web01 ~]# yum install nginx -y

3、配置nginx

[root@web01 ~]# vim /etc/nginx/conf.d/git_jenkins.conf
server {
server_name 10.0.0.7;
listen 80;
root /code/html;
index index.php index.html;
}

4.创建代码存放目录

[root@web01 ~]# mkdir /code

5、启动nginx并加入开机自启动

[root@web01 ~]# systemctl start nginx
[root@web01 ~]# systemctl enable nginx

进行代码自动上线测试

整个流程是gitlab上的仓库master分支只要做了改动就会通知jenkins服务器,然后jenkins触发构建器拉取gitlab上的代码内容,最后执行shell脚本,把代码推送到web上实现代码的自动上线。

1、gitlab端操作

为了直观的看到代码变化,我们修改主页index.html文件,这里我们方便演示,直接在root用户的master分支进行修改,实际生产环境中是不允许这样做的,切记。

修改步骤和上面讲解gitlab的分支保护步骤一样,我们修改43行的文字改成张恩清ichn.me

2、修改完成后查看jenkins端

这里我们已经自动构建成功了,蓝色代表成功,红色代表失败

3、web端操作

在浏览器上输入web服务器地址http://10.0.0.7查看效果

这样一个自由风格的jenkins代码自动上线就创建完成了,接下来我们做一个Pipeline项目

jenkins Pipeline项目

1、什么是持续集成、持续部署、持续交付

持续集成 (Continuous integration)

是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员

每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动

化测试)来验证,从而尽早地发现集成错误。

比如(你家装修厨房,其中一项是铺地砖,边角地砖要切割大小。如果一次全切割完再铺上去,发现尺寸有误的话

浪费和返工时间就大了,不如切一块铺一块。这就是持续集成。)

持续部署(continuous deployment)

是通过自动化的构建、测试和部署循环来快速交付高质量的产品。某种程度

上代表了一个开发团队工程化的程度,毕竟快速运转的互联网公司人力成本会高于机器,投资机器优化开发流程化

相对也提高了人的效率。

比如(装修厨房有很多部分,每个部分都有检测手段,如地砖铺完了要测试漏水与否,线路铺完了要通电测试电路

通顺,水管装好了也要测试冷水热水。如果全部装完了再测,出现问题可能会互相影响,比如电路不行可能要把地

砖给挖开……。那么每完成一部分就测试,这是持续部署。) 

持续交付 (Continuous Delivery)

频繁地将软件的新版本,交付给质量团队或者用户,以供评审尽早发现生产环境

中存在的问题;如果评审通过,代码就进入生产阶段

比如(全部装修完了,你去验收,发现地砖颜色不合意,水池太小,灶台位置不对,返工吗?所以不如没完成一部

分,你就去用一下试用验收,这就是持续交付。)

敏捷思想中提出的这三个观点,还强调一件事:通过技术手段自动化这三个工作。加快交付速度。

2、pipeline简介

1、什么是pipeline

Jenkins 2.0的精髓是Pipeline as Code,是帮助Jenkins实现CI到CD转变的重要角色。什么是Pipeline,简单

来说,就是一套运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个

任务难以完成的复杂发布流程。Pipeline的实现方式是一套Groovy DSL,任何发布流程都可以表述为一段Groovy

脚本,并且Jenkins支持从代码库直接读取脚本,从而实现了Pipeline as Code的理念。 

2、pipeline概念

Pipeline 是一个用户定义的 CD 流水线模式。Pipeline 代码定义了通常包含构建、测试和发布步骤的完整的构

建过程。

Node 

    node 是一个机器,它是 Jenkins 环境的一部分,并且能够执行 Pipeline。同时,node 代码块也是脚本式 

Pipeline 语法的关键特性。 

Stage 

    Stage 块定义了在整个 Pipeline 中执行的概念上不同的任务子集(例如“构建”,“测试”和“部署”阶段),

许多插件使用它来可视化或呈现 Jenkins 管道状态/进度。 

Step 

    一项任务。从根本上讲,一个步骤告诉 Jenkins 在特定时间点(或过程中的“步骤”)要做什么。例如,使用 

sh step:sh 'make' 可以执行 make 这个 shell 命令。 

3、jenkins file (语法)

声明式 脚本式 

脚本式语法格式:

pipeline{ 
agent any 
stages{ 
    stage("get code"){ 
       steps{ 
           echo "get code from scm" 
       } 
    } 
    stage("package"){ 
        steps{ 
            echo "packge code" 
        } 
    } 
    stage("deploy"){ 
        steps{ 
            echo "deploy packge to node1" 
        } 
    } 


4、创建一个pipeline项目 

为了更直观的看到效果,这里我把jenkins自由风格的项目先删除

5、配置pipeline项目 

丢弃就得构建和触发器设置和自由风格项目设置步骤是一样的

设置Definition

第一种方法,直接在jenkins端填写脚本,这样的弊端是出现错误后要gitlab端和jenkins端来回切换修改比较麻烦

手动构建查看效果

构建成功,pipeline配置可以看到每一步的日志,可以知道那个步骤出错

第二种配置方法

gitlab端新建一个文件,文件名称和上面Script Path名称保持一致

这里标注的名称是文件名,jenkins,gitlab文件还有脚本内用里的名称一定要一致

附上代码

pipeline{
agent any
stages{
stage("get code"){
steps{
echo "get code"
}
}
stage("unit test"){
steps{
echo "unit test"
} }
stage("package"){
steps{
sh 'tar zcf /opt/web‐${BUILD_ID}.tar.gz ./* --exclude=./git --exclude=./Jenkinsfile'
} }
stage("deploy"){
steps{
sh 'ssh 10.0.0.7 "cd /code && mkdir web‐${BUILD_ID}"'
sh 'scp /opt/web‐${BUILD_ID}.tar.gz 10.0.0.7:/code/web‐${BUILD_ID}'
sh 'ssh 10.0.0.7 "cd /code/web‐${BUILD_ID} && tar xf web‐${BUILD_ID}.tar.gz && rm -rf web‐${BUILD_ID}.tar.gz"'
sh 'ssh 10.0.0.7 "cd /code && rm -rf html && ln -s web‐${BUILD_ID} /code/html"'
}
} }
}

做一下测试,还是修改主页index.html内容,修改方式与上面测试上的步骤一样

我们这里修改成欢迎来访张恩清博客园

修改完成查看jenkins和web端的效果

git+jenkins自动上线总结

基本流程

客户提出需求,公司进行分析,分析结束开发开始准备代码,公司内部测试代码,初步测试无误后提交到gitlab服务器上,然后通过jenkins服务器推送到测试服务器上,经过测试发现没有任何问题以后就可以推送到生产环境上,如果出现bug,那么开发人员将进行修改,修改完成提出合并请求交给开发经理(开发的老大)进行审核,开发经理审核通过后确认合并,然后gitlab通知jenkins服务器触发构建,然后到线上环境。

运维人员则是负责搭建和维护gitlab和jenkins服务器,配合开发进行代码的上线。

声明

此篇文章是本人经过层层实验,多次操作,确保操作无误,尽可能让基础较差的朋友可以按照文章步骤完成代码自动上线的操作,由于内容较多,排版和内容上可能会出现小的错误,大家可以积极指正,码字不易,转载请注明出处,谢谢。

GIt+jenkins代码自动上线的更多相关文章

  1. devops持续集成,Centos7.6下gitlab+jenkins(pipeline)实现代码自动上线

    持续集成 gitlab+jenkins(pipeline)实现代码自动上线 环境准备:Centos7.6版本ip:192.168.0.13 主机名:gitip:192.168.0.23 主机名:jen ...

  2. jenkins代码自动部署

    jenkins是一个广泛用于持续构建的可视化web工具,持续构建说得更直白点,就是各种项目的"自动化"编译.打包.分发部署.jenkins可以很好的支持各种语言(比如:java, ...

  3. Git提交代码自动触发JenKins构建项目

    1.需求场景 用户提交代码后自动触发jenkins构建项目 流程图如下: 2.JenKins安装Gitlab Hook Plugin插件 3.JenKins配置 4.Gitlab Hook Plugi ...

  4. Jenkins代码自动部署相关文档

    环境 centos 7.0+ Java JDK 1.8+ jenkins 2.220 maven 3.0+ git 1.8+ 注意事项 一. linux 安装 JDK (jdk-8u201-linux ...

  5. 搭建Git服务器环境----Git hooks代码自动部署

    引言:自己想搭一套git的服务端环境,不想用github码云等.经多方资料整合,实验总结,以下是亲测有效的方式.可用于公司日常开发 一.搭建Git环境 ① 安装 Git Linux 做为服务器端系统, ...

  6. Jenkins介绍和安装及配合GitLab代码自动部署

    Jenkins是什么? 基于JAVA的开源的自动化系统平台 加速自动化CI,CD任务及流水线,所有类型的任务:构建,测试,部署等 丰富的插件生态系统支持功能扩展,1400+插件和SCM,测试,通知,报 ...

  7. Jenkins之自动部署、代码安全扫描、自动化接口测试

    搭建Jenkins wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.reporpm --i ...

  8. 自动提交Git branch代码评审到Review Board系统

    背景 敏捷软件开发中,越小的反馈环,意味着软件质量越容易得到保证. 作为组件团队,我们的开发任务中,往往存在一些特性涉及到几十个功能点,开发周期持续数周或数月的情况.如何在开发过程中保证软件质量,是个 ...

  9. 做了一个简易的git 代码自动部署脚本

    做了一个简易的git 代码自动部署脚本 http://my.oschina.net/caomenglong/blog/472665 发表于2个月前(2015-06-30 21:08)   阅读(200 ...

随机推荐

  1. 从虚拟机角度看Java多态->(重写override)的实现原理

    工具与环境:Windows 7 x64企业版Cygwin x64jdk1.8.0_162 openjdk-8u40-src-b25-10_feb_2015Vs2010 professional 0x0 ...

  2. 私网IP访问Internet

    公网.内网是两种Internet的接入方式. 内网接入方式:上网的计算机得到的IP地址是Internet上的保留地址,保留地址有3种形式: A类地址:10.0.0.0~10.255.255.255 B ...

  3. C/C++函数指针,指针函数的用法,用处

     先看函数指针 int func2(int x); /* 声明一个函数 */ int (*q2) (int x); /* 声明一个函数指针 */ q2=func2;    /* 将func函数的首地址 ...

  4. matlab练习程序(随机粒子切换特效)

    视频制作软件中一般都会有相邻帧切换的特效,我过去用过vagas好像就有很多切换特效. 我想这个也算是其中一种吧,虽然我不确定实际中到底有没有这种切换. 实际上我只是下班后太无聊了,写着玩的,没什么高深 ...

  5. Python 基于固定 IP 来命名 ARM 虚拟机的实现

    问题描述 希望通过 Python 批量创建 ARM 虚拟机,并且在虚拟机命名时加入固定 IP 信息,方便管理维护. 问题分析 在创建 ARM 虚拟机之前,先创建固定 IP,然后获取固定 IP 地址,创 ...

  6. 框架页面jquery装载

  7. Linux--LAMP平台搭建

    LAMP平台搭建 准备工作 rpm -e php php-cli php-ldap php-commn php-mysql --nodeps 删除php相关依赖软件 rpm -ivh zlib-dev ...

  8. Git warning push.default is unset

    warning: push.default is unset; its implicit value is changing in Git 2.0 from 'matching' to 'simple ...

  9. Android应用经典主界面框架之中的一个:仿QQ (使用Fragment, 附源代码)

    备注:代码已传至https://github.com/yanzi1225627/FragmentProject_QQ 欢迎fork,如今来审视这份代码,非常多地方写的不太好,欢迎大家指正.有时间我会继 ...

  10. 记忆化搜索,FatMouse and Cheese

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1107 http://acm.hdu.edu.cn/showpro ...