本文由AlvinZH所写,欢迎学习引用,如有错误或更优化方法,欢迎讨论,联系方式QQ:1329284394。

前言

动态规划(Dynamic Programming),是一个神奇的东西。DP只能意会,不可言传。大家在做DP题的时候一定要理清思路,一般是先不管空间,毕竟以空间换时间,大多数题都是先卡时间再卡空间的。

DP具备的两个要素:最优子结构和子问题重叠,见《算法导论》225页。简单来讲就是问题是一个由多决策产生最优值的最优化问题。

  • 最优化原理:其子问题的最优会导致全局最优,具有最优子结构的性质。这是运用DP的"前提",是否符合最优化原理是一个问题的本质特征。如果不满足最优化原理,那最开始所做的决策都是徒劳的。
  • 无后效性:当前状态如果确定,以后过程的演变将不再受当前状态以前的各状态和以前的决策影响。这是运用DP的"条件",DP按次序去求每阶段的解,如果一个问题有后效性,那么这样的次序便是不合理的。一个问题的某个DP决策方法可能具有后效性,通过重新划分阶段,重新选定状态,或者增加状态变量的个数等手段,是可以把问题转化为满足无后效性的。所以决策的"顺序"也是问题的关键。

接下来通过几道经典的题目,简单练习一下DP,比赛题目连接:BUAAOJ-DP大作战 H~M题。

899 AlvinZH掉坑里了(H)

思路

简单DP。简单判断符合运用DP要求,求得到达某个点的最大金币数,至多只要比较两点(左点&上点)的最大金币数,即满足最优子结构。

\(dp[i][j]\) :表示走到点(i,j)时取得的最大金币数。

状态转移方程: \(dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]) + M[i][j]\) 。

小技巧:①初始化为-INF;②真实数据存于[1n][1m]中,边缘统一。

参考代码

//
// Created by AlvinZH on 2017/10/17.
// Copyright (c) AlvinZH. All rights reserved.
// #include <cstdio>
#include <cstring>
#define INF 0x3f3f3f3f int M[505][505];//矩阵数据
int dp[505][505];//到达点(i,j)时最大金币个数 inline int MAX(int i, int j) {
if(dp[i - 1][j] > dp[i][j - 1]) return dp[i - 1][j];
else return dp[i][j - 1];
} int main()
{
int n, m;
while(~scanf("%d %d", &n, &m))
{
memset(dp, -INF, sizeof(dp));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
scanf("%d", &M[i][j]); dp[1][1] = M[1][1];
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if(dp[i][j] < 0) dp[i][j] = MAX(i, j) + M[i][j]; printf("%d\n", dp[n][m]);
}
} /*
* 简单DP
* dp[i][j]表示走到点(i,j)时取得的最大金币数。
* 状态转移方程:dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]) + M[i][j]。
*/

900 AlvinZH又掉坑里了(I)

思路

难题。

错误思路:贪心。运用上一题的写法,先走一次,路径置零,再来一次,两次最大值相加。你会发现你样例都过不了(要是放个恰好满足的样例不知道要WA多少次)。仔细一想,两次最优加起来还会是最优吗?真不一定,看这题就知道了。

既然不能分两次处理,那就同步处理吧。如何同步呢?多路DP,即想象两个人同时从左上走到右下,保证在同一点只取一次,求两人最大金币数和。用四维数组dp[205][205][205][205]?看着就挺吓人的,不过简单易懂,状态转移方程也可以很快得出:dp[i][j][x][y]=max{dp[i-1][j][x-1][y],dp[i-1][j][x][y-1],dp[i][j-1][x-1][y],dp[i][j-1][x][y-1]},代表两人到达(i,j)和(x,y)时的最大金币数。虽然明知会MLE,这一步的思考是有必要的,因为这是优化的基础。

发现惊喜:上述状态转移方程四个决策中有 \(i+j=x+y\) ,故可以轻易的把四维降成三维。这里有两种方法优化:

  • 第一种方法稍微作优化,需要dp[405][205][205]。其中dp[step][x][y]:表示第step步时(两人一起走),第一个人在第x行,第二个人在第y行的最大收益,答案为dp[m + n][n][n]。两人坐标为(x,step-x)、(y,step-y),两个人在同一行时,一定在同一列,需要注意走到同一点时的处理方法。状态转移如下,四种决策(下下,下右,右下,右右)去最优,具体见参考代码一。
  //下下,下右,右下,右右四者取最大值
dp[i][j][k] = MAX(dp[i-1][j-1][k-1], dp[i-1][j][k-1], dp[i-1][j-1][k], dp[i-1][j][k]);
if (j == k)//走到同一行,必定在同一列,所以确定到达A[j][i - j]同一点
dp[i][j][k] += M[j][i-j];
else//走到不同行,所以确定到达A[j][i-j]、A[k][i-k]两点。
dp[i][j][k] += (M[j][i-j] + M[k][i-k]);
  • 第二种方法优化更佳,也易懂,需要dp[205][205][205]。其中dp[i][j][k]表示第一个人走到(i,j),第二个人走到横坐标为k,由于两人一起走,可以算出第二人坐标为(k,i+j-k)。这里可以直接避免走到同一点,k!=i即可。状态转移方程如下,同样是取四种决策最优,具体见参考代码二。
  for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
for(int k = 1; k <= n && k <= (i+j); ++k)
{
int t = (i+j)-k;
if ( k != i )//保证不重复
dp[i][j][k] = M[i][j]+M[k][t]+MAX(dp[i-1][j][k],dp[i][j-1][k],dp[i-1][j][k-1],dp[i][j-1][k-1]);
}

这两种优化很相似,而第二种比第一种空间整整小了一倍,有人问为什么还要放在这里讨论,因为,第一种方法还可以继续优化,我们发现,在状态转移方程中,dp[i][][]只与dp[i-1][][]有关,这意味着什么?这意味着可以把第一维继续优化,即数组变为dp[2][205][205],采用滚动数组,把第一维循环利用。状态转移方程如下,具体可见参考代码三。

  int cur = 0;
for (int i = 2; i <= n + m; i++) {
cur ^= 1;
for (int j = 1; j <= n&&i - j >= 0; j++) {
for (int k = 1; k <= n&&i - k >= 0; k++) {
//下下,下右,右下,右右四者取最大值
dp[cur][j][k] = MAX(dp[cur^1][j-1][k-1], dp[cur^1][j][k-1], dp[cur^1][j-1][k], dp[cur^1][j][k]);
if (j == k)//走到同一行,必定在同一列,所以确定到A[j][i - j]一点
dp[cur][j][k] += M[j][i-j];
else//走到不同行,所以确定到A[j][i-j]、A[k][i-k]两点。
dp[cur][j][k] += (M[j][i-j] + M[k][i-k]);//右右
}
}
}

三种方法评测记录对比如下:

参考代码一

//
// Created by AlvinZH on 2017/10/17.
// Copyright (c) AlvinZH. All rights reserved.
// #include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std; int m, n;
int M[201][201];
int dp[402][201][201]; inline int MAX(int a, int b, int c, int d) {
int minAns = a;
if(minAns < b) minAns = b;
if(minAns < c) minAns = c;
if(minAns < d) minAns = d;
return minAns;
} int main()
{
while(~scanf("%d%d", &n, &m))
{
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &M[i][j]); for (int i = 2; i <= n + m; i++) {
for (int j = 1; j <= n && i - j >= 0; j++) {
for (int k = 1; k <= n && i - k >= 0; k++) {
//下下,下右,右下,右右四者取最大值
dp[i][j][k] = MAX(dp[i-1][j-1][k-1], dp[i-1][j][k-1], dp[i-1][j-1][k], dp[i-1][j][k]);
if (j == k)//走到同一行,必定在同一列,所以确定到达A[j][i - j]同一点
dp[i][j][k] += M[j][i-j];
else//走到不同行,所以确定到达A[j][i-j]、A[k][i-k]两点。
dp[i][j][k] += (M[j][i-j] + M[k][i-k]);
}
}
}
printf("%d\n",dp[n + m][n][n]);
}
return 0;
}

参考代码二

//
// Created by AlvinZH on 2017/10/17.
// Copyright (c) AlvinZH. All rights reserved.
// #include <cstdio>
#include <iostream>
#include <cstring>
using namespace std; int m, n;
int M[201][201];
int dp[201][201][201]; inline int MAX(int a, int b, int c, int d) {
int minAns = a;
if(minAns < b) minAns = b;
if(minAns < c) minAns = c;
if(minAns < d) minAns = d;
return minAns;
} int main()
{
while(~scanf("%d%d", &n, &m))
{
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
scanf("%d", &M[i][j]); dp[1][1][1] = M[1][1]; for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
for(int k = 1; k <= n && k <= (i+j); ++k)
{
int t = (i+j)-k;
if ( k != i )//保证不重复
dp[i][j][k] = M[i][j]+M[k][t]+MAX(dp[i-1][j][k],dp[i][j-1][k],dp[i-1][j][k-1],dp[i][j-1][k-1]);
}
printf("%d\n", dp[n][m-1][n-1] + M[n][m]);
}
}

参考代码三(最优)

//
// Created by AlvinZH on 2017/10/17.
// Copyright (c) AlvinZH. All rights reserved.
// #include <cstdio>
#include <cstring>
#include <iostream>
using namespace std; int m, n;
int M[201][201];
int dp[2][201][201]; inline int MAX(int a, int b, int c, int d) {
int minAns = a;
if(minAns < b) minAns = b;
if(minAns < c) minAns = c;
if(minAns < d) minAns = d;
return minAns;
} int main()
{
while(~scanf("%d%d", &n, &m))
{
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &M[i][j]); //发现每一步只与前一步有关,可以滚动数组,把一维滚动掉。
int cur = 0;
for (int i = 2; i <= n + m; i++) {
cur ^= 1;
for (int j = 1; j <= n&&i - j >= 0; j++) {
for (int k = 1; k <= n&&i - k >= 0; k++) {
//下下,下右,右下,右右四者取最大值
dp[cur][j][k] = MAX(dp[cur^1][j - 1][k - 1], dp[cur^1][j][k - 1], dp[cur^1][j - 1][k], dp[cur^1][j][k]);
if (j == k)//走到同一行,必定在同一列,所以确定到A[j][i - j]一点
dp[cur][j][k] += M[j][i - j];
else//走到不同行,所以确定到A[j][i - j]、A[k][i - k]两点。
dp[cur][j][k] += (M[j][i - j] + M[k][i - k]);//右右
}
}
}
printf("%d\n",dp[cur][n][n]);
}
return 0;
}

901 AlvinZH双掉坑里了(J)

思路

简单DP。简化问题:将n个金币放入m个盒子,无空盒。

直接上dp吧,dp[i][j]:将i个金币放入j个盒子的方法数。此题的关键在于如何找到状态转移方程,很有可能会计算重复的方法。我们把答案分成两部分:

①放完之后所有盒子金币数量大于1;
②放完之后至少有一个盒子金币数量为1。

这样分可以保证不会有重复计算。状态转移方程: \(dp[i][j] = dp[i-j][j] + dp[i-1][j-1]\) 。

① \(dp[i-j][j]\) :将(i-j)个金币放到j个盒子,然后这j个盒子每个再放1个金币。表示的是将i个金币分成所有盒子金币数量大于1的方案总数。例如,求9分解成3份,6(9-3)分成3份可以分为{1,1,4}{1,2,3}{2,2,2},则9可以分为{2,2,5}{2,3,4}{3,3,3},共3种。

② \(dp[i-1][j-1]\) :将(i-1)个金币放到(j-1)个盒子,再来一个盒子放1个。表示的是将i个金币分成至少有一个盒子金币数量为1的方案总数。例如,求9分解成3份,8(9-1)分成2份可以分为{1,7}{2,6}{3,5}{4,4},则9可以分为{1,1,7}{1,2,6}{1,3,5}{1,4,4},共4种。

难点在于如何避免重复,这里处理得十分巧妙,请细细体会。

参考代码

//
// Created by AlvinZH on 2017/10/23.
// Copyright (c) AlvinZH. All rights reserved.
// #include <cstdio>
#include <cstring>
#define MOD 1000007 int n, m;
int dp[10005][1005]; int main()
{
while(~scanf("%d %d", &n, &m))
{
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if(i - j >= 0)
dp[i][j] = (dp[i-j][j] + dp[i-1][j-1]) % MOD;
}
} printf("%d\n", dp[n][m]);
}
}

902 AlvinZH叒掉坑里了(K)

思路

简单DP。与上一题十分相似,问题简化为:将n个金币放入至多m个盒子,不存在相等数量金币的盒子。

dp[i][j]:将i个金币放入j个盒子的方法数。本题同样可以沿用上一题思想,把答案分成两部分。但是有一个问题是不能有相同数量金币的盒子,如果像上一题一样处理,我们会出现多个1的情况,需要避免这些情况。

①放完之后所有盒子金币数量大于1;
②放完之后只有一个盒子金币数量为1。

这样分可以保证不会有重复计算,而且不会有相同。状态转移方程: \(dp[i][j] = dp[i-j][j] + dp[i-j][j-1]\) 。

① \(dp[i-j][j]\) :将(i-j)个金币放到j个盒子,然后这j个盒子每个再放1个金币。表示的是将i个金币分成所有盒子金币数量大于1的方案总数。

② \(dp[i-j][j-1]\) :将(i-j)个金币放到(j-1)个盒子,然后这(j-1)个盒子每个再放1个金币,最后再来一个盒子放1个金币。表示的是将i个金币分成至少有一个盒子金币数量为1的方案总数。

对比上一题,状态转移方程仅仅差了一个字符

难点在于如何避免重复以及相同数目,这里处理得十分巧妙,请细细体会。

优化问题

本题需要注意内存限制,dp[50005][50005]是会MLE的。由于本题要求分成不同的数目,1+2+3+...+m=n,可以得到 \(m<sqrt(2_n)\) ,于是dp数组变成dp[50005][350]。时间复杂度为 \(O(n_sqrt(2n))\) 。具体见参考代码一。

与第二题相似,我们发现,dp[i][j]只与dp[][j]和dp[][j-1]有关,那么这里可以对空间再次优化,dp数组变为dp[50005][2],具体操作见参考代码二。真tm神奇啊~

参考代码一

//
// Created by AlvinZH on 2017/10/23.
// Copyright (c) AlvinZH. All rights reserved.
// //正常写法
#include <cstdio>
#include <cstring>
#define MOD 1000007 int n;
int dp[50005][350]; int main()
{
while(~scanf("%d", &n))
{
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
int ans = 0; for (int i = 1; i < 350; ++i) {
for (int j = 0; j <= n; ++j) {
if(j - i >= 0)
dp[j][i] = (dp[j-i][i] + dp[j-i][i-1]) % MOD;
}
ans = (ans + dp[n][i]) % MOD;
} printf("%d\n", ans);
}
}

参考代码二(最优)

#include <cstdio>
#include <cstring>
#define MOD 1000007 int n;
int dp[50005][2]; int main()
{
while(~scanf("%d", &n))
{
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
int ans = 0; for (int i = 1; i < 350; ++i) {
for (int j = 0; j < 350; ++j)//每次操作初始化
dp[j][i&1] = 0; for (int j = 0; j <= n; ++j) {
if (j - i >= 0)
dp[j][i&1] = (dp[j - i][i&1] + dp[j - i][(i - 1)&1]) % MOD;
}
ans = (ans + dp[n][i&1]) % MOD;
} printf("%d\n", ans);
}
}

903 AlvinZH叕掉坑里了(L)

思路

难题。本题已经超越了dp,但其本质还是dp。简化题目:将一个数拆成一个或多个数的和,即无序整数拆分问题。

无序整数拆分问题是欧拉五边形数定理的一个应用。详情请查看:分拆数 && hdu 4651 && hdu 4658

证明五边形数定理以及证明无序拆分整数是五边形数定理的应用,这。。。就超出我的知识范围了。

参考代码

//
// Created by AlvinZH on 2017/10/23.
// Copyright (c) AlvinZH. All rights reserved.
// #include <cstdio>
#include <cstring>
#define MaxSize 50005
#define MOD 1000007
#define f(x) (((x) * (3 * (x) - 1)) >> 1)
#define g(x) (((x) * (3 * (x) + 1)) >> 1) using namespace std; int n, ans[MaxSize]; void init()
{
memset(ans, 0, sizeof(ans));
ans[0] = 1;
for (int i = 1; i <= 50000; ++i) {
for (int j = 1; f(j) <= i; ++j) {
if (j & 1)
ans[i] = (ans[i] + ans[i - f(j)]) % MOD;
else
ans[i] = (ans[i] - ans[i - f(j)] + MOD) % MOD;
}
for (int j = 1; g(j) <= i; ++j) {
if (j & 1)
ans[i] = (ans[i] + ans[i - g(j)]) % MOD;
else
ans[i] = (ans[i] - ans[i - g(j)] + MOD) % MOD;
}
}
} int main()
{
init();
while (~scanf("%d", &n))
{
printf("%d\n", ans[n]);
}
} /*
* 欧拉五边形定理:P(n)表示n的划分种数。
* P(n) = ∑{P(n - k(3k - 1) / 2 + P(n - k(3k + 1) / 2 | k ≥ 1}
* n < 0时,P(n) = 0;n = 0时, P(n) = 1即可。
*/

916 AlvinZH不想掉坑里了(M)

分析

中等题。单源最短路径。最短路径是一个经典算法问题,所以我为其特地单独写了一篇随笔,仅供参考。

AlvinZH又来骗访客量啦:四大算法解决最短路径问题

参考代码

//
// Created by AlvinZH on 2017/11/3.
// Copyright (c) AlvinZH. All rights reserved.
// #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int N=100010;
const int INF = 0x3f3f3f3f; bool Vis[N];//是否被访问过
int Dis[N];//距离 struct DisAndStart
{
int dis;//距离
int start;//起点
bool operator < (const DisAndStart& p)const {
return p.dis<dis;
}
DisAndStart(int d, int s):dis(d),start(s){}
}; vector<pair<int, int> > V[N];//二维的vector数组 void dijkstra(int s)
{
priority_queue<DisAndStart> Q;
memset(Dis,INF,sizeof(Dis));
memset(Vis,0,sizeof(Vis)); Dis[s]=0;
Q.push(DisAndStart(0,s));
while(!Q.empty())
{
DisAndStart p=Q.top();
Q.pop();
if(Vis[p.start]) continue;//已经访问过该点
Vis[p.start]=1;
for(int t=0;t<V[p.start].size();t++)
{
int end=V[p.start][t].first;
int Time=V[p.start][t].second;
if(Dis[p.start]+Time<Dis[end])
{
Dis[end]=Dis[p.start]+Time;
Q.push(DisAndStart(Dis[end],end));
}
}
}
}
int main()
{
//freopen("in2.txt", "r", stdin);
//freopen("out2.txt", "w", stdout);
int n, m, k, des;
int x, y, Time;
while(~scanf("%d%d%d", &n, &m, &k))
{
for(int i = 1; i <= n; i++)//清空数据
V[i].clear();
while(m--)
{
scanf("%d%d%d", &x, &y, &Time);
V[x].push_back(make_pair(y, Time));
V[y].push_back(make_pair(x, Time));
}
dijkstra(1);
int cnt = 1;
for(int i = 0; i < k; ++i)
{
scanf("%d", &des); if(Dis[des] == INF) printf("Case %d:-1\n", cnt);
else printf("Case %d:%d \n", cnt, Dis[des]);
cnt++;
}
printf("\n");
}
}

AlvinZH掉坑系列讲解(背包DP大作战H~M)的更多相关文章

  1. 851 AlvinZH的鬼畜密码(背包DP大作战N)

    851 AlvinZH的鬼畜密码 思路 难题.动态规划. 先判断字符串是否合理(可翻译),然后分段处理,每一小段用动态规划求出解法数. dp[i]:字符串str[0~i]的解法数.通过判断str[i] ...

  2. 963 AlvinZH打怪刷经验(背包DP大作战R)

    963 AlvinZH打怪刷经验 思路 这不是一道普通的01背包题.大家仔细观察数据的范围,可以发现如果按常理来的话,背包容量特别大,你也会TLE. 方法一:考虑01背包的一个常数优化----作用甚微 ...

  3. 976 AlvinZH想回家(背包DP大作战T)

    976 AlvinZH想回家 思路 如果在第i小时有一些飞机延误,那么一架飞机的c值越大,这一小时产生的损失也越大.而使这一小时产生的损失尽可能的小并不会导致接下来时间产生的损失增大.因此应当每一小时 ...

  4. 977 AlvinZH过生日(背包DP大作战S)

    977 AlvinZH过生日 思路 难题.逆推DP. 要明确dp的状态只与是否有选择权有关,而与选择权在谁手里无关.因为不论选择权在谁手里,那个人都会尽可能的获得最大的蛋糕重量. dp[i]表示分配到 ...

  5. 991 AlvinZH的奇幻猜想----整数乘积plus(背包DP大作战P)

    914 AlvinZH的奇幻猜想----整数乘积puls 思路 难题.动态规划. 将数字串按字符串输入,处理起来更方便些. dp[i][j]:表示str[0~i]中插入j个乘号时的乘积最大值.状态转移 ...

  6. 906 AlvinZH的奇幻猜想----整数乘积(背包DP大作战O)

    906 AlvinZH的奇幻猜想----整数乘积 思路 难题.动态规划. 将数字串按字符串输入,处理起来更方便些. dp[i][j]:表示str[0~i]中插入j个乘号时的乘积最大值.状态转移方程为: ...

  7. DP大作战—组合背包

    题目描述 组合背包:有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包). DD大牛的伪代码 for i = 1 to N if 第i件物品属 ...

  8. DP大作战——多重背包

    题目描述 在之前的上机中,零崎已经出过了01背包和完全背包,也介绍了使用-1初始化容量限定背包必须装满这种小技巧,接下来的背包问题相对有些难度,可以说是01背包和完全背包的进阶问题. 多重背包:物品可 ...

  9. DP大作战—状态压缩dp

    题目描述 阿姆斯特朗回旋加速式阿姆斯特朗炮是一种非常厉害的武器,这种武器可以毁灭自身同行同列两个单位范围内的所有其他单位(其实就是十字型),听起来比红警里面的法国巨炮可是厉害多了.现在,零崎要在地图上 ...

随机推荐

  1. Android ScrollView监听滑动到顶部和底部的两种方式(你可能不知道的细节)

    Android ScrollView监听滑动到顶部和底部,虽然网上很多资料都有说,但是不全,而且有些细节没说清楚 使用场景: 1. 做一些复杂动画的时候,需要动态判断当前的ScrollView是否滚动 ...

  2. 帮公司人事MM做了个工资条拆分工具

    引言 偶尔一次午饭时人事说加班加到8点多,纯手工复制粘贴Excel的内容,公司大概150多人吧,每次发工资时都需要这样手动处理,将一个Excel拆分成150多个Excel,再把里面的内容粘过去,如此循 ...

  3. angularjs 菜鸟教程 版本1.4.6

    最简angularJS webstorm代码提示 在 head 里面添加:<script src="https://ajax.googleapis.com/ajax/libs/angu ...

  4. java获取文件大小

    1.使用File的length()方法获取.这个方法获取的字节数,由于返回的是Long类型所以能返回的最大值是Long.MAX_VALUE File file = new File( "D: ...

  5. 201521123052《Java程序设计》第5周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 学习了更多markdown的知识 参考资料: 百度脑图 XMind 2. 书面作 ...

  6. Maven+SSM框架搭建【spring+springmvc+mybatis】

    本案例用到:ssm[spring+springmvc+mybatis]框架 数据库:mysql (推荐使用mysql 或者 sqlserver  .oracle太大,一般大型项目才会用到) 开发工具: ...

  7. Linux qemu-nbd mount qemu disk image

    Linux qemu-nbd mount qemu disk image deepin@deepin:~$ deepin@deepin:~$ qemu-nbd --help Usage: qemu-n ...

  8. Maven的SSM框架配置文件:

    applicationContext.xml: <?xml version="1.0" encoding="UTF-8"?> <beans x ...

  9. bisect模块用于插入

    参考链接: chttp://www.cnblogs.com/skydesign/archive/2011/09/02/2163592.html水

  10. virtualBox安装centos7并配置nginx php mysql运行环境

    virtualBox安装centos7并配置nginx php mysql运行环境 一:virtualBox安装centos7并进行基础设置 1.下载dvd.iso安装文件,下载地址:https:// ...