本文持续更新……
1 给定两组序列 求上下匹配的最大值(POJ1692 Crossed Matchings)
题意:给出两行数,求上下匹配的最多组数是多少。
匹配规则:
1 匹配对的数字必须相同
2 每个匹配必须有且只能有一个匹配与之相交叉,且相交叉的两组匹配数字必须不同
3 一个数最多只能匹配一次
思路:
dp[i][j]表示上面取i个数,下面取j个数的最大匹配数
1)若上面不匹配或下面不匹配,则dp[i][j] = max(dp[i - 1][j], dp[i][j - 1] )
2)若a[i] != b[j], 从i向左找最大k1使b[j] = a[k1],从j向左找最大k2使a[i] = b[k2],
则dp[i][j] = max(dp[i][j], dp[k1 - 1][k2 - 1] + 2 )
2 过河问题(POJ1700 Crossing River)
题意:每次过桥的时候最多两个人,如果桥这边还有人,那么还得回来一个人(送手电筒),求最短时间。
思路:
首先,每次让最快的人回来是错的。
先按时间递增排序,dp[i]表示前i个人过河的最短时间
1)若有i - 1个人过河,则让最快的人将手电筒送回,时间为dp[i - 1] + t[0] + t[i]
2)若有i - 2个人过河,让最快的人把手电筒送过来,然后第i个人和另外一个人一起过河,由于花费时间最少的人在这边,所以下一次送手电筒过来的一定是花费次少的,送过来后花费最少的和花费次少的一起过河,时间为dp[i - 2] + t[0] + t[i] + 2 * t[1]
故dp[i] = min(dp[i - 1] + t[0] + t[i], dp[i - 2] + t[0] + t[i] + 2 * t[1])
3 括号匹配问题
POJ2955 Brackets
区间dp,dp[i][j]表示从i到j匹配的最大数,则
1)若第i,j可匹配,dp[i][j] = dp[i+1][j-1] + 2
2)枚举中间点k(i <= k < j), dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j])
求这两者最大值。
4 方块消除
POJ1390 Blocks
题意:一排带有颜色的砖块,每一个可以消除相同颜色的砖块,,每一次可以到块数k的平方分数,求分数最大值
思路:dp[i][j][k]表示从第i到第j个段, 并且第j个段后面还有k个不与j相邻但颜色与j相同的方块数。
记忆化搜索:
1)若i = j, 则dp[l][r][k] = (len[l] + k) * (len[l] + k)
2)直接消除,dp[l][r][k] = dfs(l, r - 1, 0) + (len[r] + k) * (len[r] + k)
否则枚举i(l <= i < r),使第i块与第r颜色块相同,dp[l][r][k] = max(dp[l][r][k], dfs(l, i, len[r] + k) + dfs(i + 1, r - 1, 0))
5 背包问题(HDU3033 I love sneakers!)
题意:给定n个集合,每个集合有一定数量的元素,取每个元素有一定的代价和价值,每个集合至少取一个元素,可取多个元素,但每个元素最多取一次,给定总的代价m,求不超过m的情况下最大价值。
思路:dp[i][j]表示前i个集合,背包容量为j时的最大价值,枚举集合,集合中的每个元素,再枚举背包容量
1)不取此元素,不变
2)取此元素,此集合之前未取任何元素,且取此元素或已选过并取此元素
故状态转移方程如下:
dp[i][k] = max(dp[i][k], dp[i - 1][k - v] + w, dp[i][k - v] + w )
状态初始化为:
dp[0][j] = 0
dp[i][j] = -INF( i >= 1)
(集合从1计数)
6 回文串问题(HDU2205 又见回文)
题意:给定两个字符串(可能为空串),求这两个串交叉组成新串的子串中的回文串的最大长度。
布尔型变量dp[i][j][k][l]表示串a从i到j,b从k到l能否组成新串,初始化为false,则采取区间动态规划。(从1计数)
for(int i = 1; i <= la + 1; i++){
for (int j = 1; j <= lb + 1; j++){
dp[i][i][j][j - 1] = dp[i][i - 1][j][j] = dp[i][i - 1][j][j - 1] = 1;
}
}
int ans = 0;
for(int l1 = 0; l1 <= la; l1++){
for(int l2 = 0; l2 <= lb; l2++){
for(int i = 1, j = i + l1 - 1; j <= la; i++, j++){
for(int k = 1, l = k + l2 - 1; l <= lb; k++, l++){
if(!dp[i][j][k][l]){
bool b1 = i <= j && a[i] == a[j] && dp[i + 1][j - 1][k][l];
bool b2 = k <= l && b[k] == b[l] && dp[i][j][k + 1][l - 1];
bool b3 = l > 0 && a[i] == b[l] && dp[i + 1][j][k][l - 1];
bool b4 = j > 0 && b[k] == a[j] && dp[i][j - 1][k + 1][l];
dp[i][j][k][l] = b1 || b2 ||b3 ||b4;
}
if(dp[i][j][k][l] && l1 + l2 > ans){
ans = l1 + l2;
}
}
}
}
}
7 POJ1737 Connected Graph
题意:给定n个不同标号的顶点,求有多少个不同的无向简单连通图。
定义f[n]为答案,f[1] = 1, f[2] = 1
方法1:
将总的数目减去不连通的数目
总的数目为2 ^ C(n, 2),计算不连通的数目方法如下:
枚举1号节点所在连通块大小为j(1 <= j < i ),此连通块节点有C(i - 1, j - 1)种选法,1号节点所在连通块有f[j]种形态,剩余i - j个节点有2^C(i - j, 2)种形态。故递推式如下:
f[i] = 2 ^ C(i, 2) - C(i - 1, j - 1) * f[j] * 2^C(i - j, 2)
方法2:
直接求连通的方案数:
f(n) = (f(k) * f(n - k) * C(n - 2 , k - 1) * ( 2 ^ k - 1)